1. Introduction and Aims

Two datasets were generated using the 10X Genomics Chromium 3’ scRNA-Seq platform:

species experiment_name run_number lane_number sequencer approximate_number_of_cells
pb straight bleed experiment 22252 5 Hiseq 4000 30,000
pb 1:1 mix experiment 24284 1 & 2 Hiseq 2500 5,000

This script details the quality control of the 1:1 mix experiment

This data has been processed using CellRanger into counts tables. This initial analysis gave the following metrics:

Pb 1:1 mix experiment (run #: 24284 lanes 1 and 2 (Hiseq 2500)):

We will load this data in and for each run:

A. Define ‘cells’

B. Filter poor quality cells out

C. Dimensionality Reduction and Clustering

D. Remove Doublets

E. Predict life Cycle Stage (Using Bulk RNA-Seq Correlation)

2. Read in the data

Load the required packages

[1] "Seurat is loaded correctly"
[1] "cowplot is loaded correctly"
[1] "gridExtra is loaded correctly"
[1] "grid is loaded correctly"
[1] "Hmisc is loaded correctly"
[1] "dplyr is loaded correctly"
[1] "scales is loaded correctly"
[1] "ggpubr is loaded correctly"
[1] "patchwork is loaded correctly"

Import GTF file

This will be helpful later on. This contains annotations for each gene:

##Import gtf file:
gtf <- read.table("../data/Reference/Pberghei.gtf", sep="\t", header = FALSE)
head(gtf)

Read in the Data

## read in 10x output 
tenx5k_raw_data <- Read10X("../data/10X/tenx_24284")

## Create Seurat object
tenx5k <- CreateSeuratObject(counts = tenx5k_raw_data, min.cells = 0, min.features = 0, project = "GCSKO")
Feature names cannot have underscores ('_'), replacing with dashes ('-')
## add experiment to meta data for merging later
tenx5k@meta.data$experiment <- "tenx5k"

## inspect
tenx5k
An object of class Seurat 
5098 features across 737280 samples within 1 assay 
Active assay: RNA (5098 features, 0 variable features)

3. Defining Cells vs. Background

Plot a knee plot and then use a mixture model to define where the cells vs. background lie

## interesting reference material for this section can be found here: https://hemberg-lab.github.io/scRNA.seq.course/processing-raw-scrna-seq-data.html 

## get the nUMIs
umi_per_barcode <- as.data.frame(tenx5k@meta.data$nCount_RNA)

## remove zeros as these have issues when you log them and make the model later:
umi_per_barcode <- as.data.frame(umi_per_barcode[!(umi_per_barcode$`tenx5k@meta.data$nCount_RNA`==0), ])

## get a rank for each barcode
barcode_rank <- rank(-umi_per_barcode[,1])

## then make into a list
lib_size <- (umi_per_barcode[,1])

## then log this
log_lib_size <- log10(umi_per_barcode[,1])

##plot
#plot(barcode_rank, log_lib_size, xlim=c(1,100000))

## order the barcode ranks
o <- order(barcode_rank)

## reorder the library size, barcode rank by their rank
log_lib_size <- log_lib_size[o]
barcode_rank <- barcode_rank[o]
lib_size <- lib_size[o]

make a mixture model to determine the knee of the plot

## set a seed for the mixture model
set.seed(-92497)

## mixture model calculation 
require("mixtools")
mix <- normalmixEM(log_lib_size)
One of the variances is going to zero;  trying new starting values.
One of the variances is going to zero;  trying new starting values.
number of iterations= 17 
## plot result
plot(mix, which=2, xlab2="log(mol per cell)")

Find where the distributions intersect (i.e. where cells vs. background is)

## identify where the split between the distributions is
p1 <- dnorm(log_lib_size, mean=mix$mu[1], sd=mix$sigma[1])
p2 <- dnorm(log_lib_size, mean=mix$mu[2], sd=mix$sigma[2])
if (mix$mu[1] < mix$mu[2]) {
    split <- min(log_lib_size[p2 > p1])
} else {
    split <- min(log_lib_size[p1 > p2])
}

## print split
split
[1] 1.724276

View the initial result

## log the barcode rank
log_barcode_rank <- log10(barcode_rank)

## plot
plot(log_barcode_rank, log_lib_size, xlim=c(1,6))
## add the split as a line on the plot
abline(h=split, col="red")

Final Figures:

## make the results of the above functions into a dataframe
df_barcodes <- as.data.frame(cbind(barcode_rank, log_lib_size, lib_size), row.names = NULL)

## add a column for if it is a cell or not
df_barcodes$cell = rownames(df_barcodes) %in% which(df_barcodes$log_lib_size > split)

## change value to a numeric
df_barcodes$cell <- as.numeric(df_barcodes$cell)

## change the 0 to a 2 for ease of handling
df_barcodes$cell[df_barcodes$cell<1] <- 2

## rename the numerics into cells or background
df_barcodes$cell[df_barcodes$cell == 1] <- "Cells"
df_barcodes$cell[df_barcodes$cell == 2] <- "Background"

## extract the cutoff for cells do you can plot the lines
boundary <- as.numeric(sum(df_barcodes$cell == "Cells"))
split <- 10^split

## make the plot
barcode_plot <- ggplot(df_barcodes, aes(x=barcode_rank, y=lib_size, colour = cell, theme_size = 40)) +
  ## make into a dot plot
  geom_point(size = 1, shape = 16) +
  ## make the axis into log and specify breaks
  scale_x_log10(breaks = trans_breaks("log10", function(x) 10^x), labels = trans_format("log10", math_format(10^.x))) +
  ## make the axis into log and specify breaks
  scale_y_log10(breaks = trans_breaks("log10", function(x) 10^x), labels = trans_format("log10", math_format(10^.x))) +
  annotation_logticks() +
  ## change colours of plot
  scale_color_manual(values=c("#bdbdbd", "#5ba43a"), labels = c("Background", "Cells")) +
  ## change aes of legend
  theme(legend.position="bottom", text = element_text(size=25), legend.text=element_text(size=25), axis.text=element_text(size=25)) +
  ## add the lines on the plot
  geom_segment(aes(x = 0, y = split, xend = boundary, yend = split), colour = "black", alpha = 0.01) +
  geom_segment(aes(x = boundary, y = 0, xend = boundary, yend = split), colour = "black", alpha = 0.01) +
  ## change the axis labels
  labs(x = "Barcodes", y = "UMI Counts", colour="Cell Designation") +
  ## change the size of the legend
  guides(colour = guide_legend(override.aes = list(size=10))) +
  ## fix axis
  coord_fixed() +
  ## make it look pretty
  theme_light()

## print the plot
barcode_plot

## save the plot
<<<<<<< HEAD
ggsave("QC_10X_barcode_plot_5k.png", plot = barcode_plot, device = "png", height = 15, width = 15, units = "cm", path = "/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/")
======= ggsave("barcode_plot_5k.png", plot = barcode_plot, device = "png", height = 15, width = 15, units = "cm", path = "../images_to_export/") >>>>>>> directory_change

so the number of cells that is retained is:


Background      Cells 
    138879       7762 

Filter the object

## extract the nCount and row names from the Seurat object
upb <- data.frame(nCount_RNA = tenx5k@meta.data$nCount_RNA, row.names = rownames(tenx5k@meta.data))

## make blank column for rank
upb$rank <- NA

## order by nCounts
order.scores <- order(upb$nCount_RNA, decreasing = TRUE)

## add a rank to this column based on the ordered nCount
upb$rank[order.scores] <- 1:nrow(upb)

## inspect
#head(upb)

## make a list of cells to retain in the Seurat object
keep_cells <- rownames(upb[which(upb$rank < 7763),])

## subset Seurat object to include cells and discard background
pb_sex <- subset(tenx5k, cells = keep_cells)

4. Filter Out Poor-Quality Cells

Filter Mitochondrial %

Mitochondrial cell counts

## extract mitochondrial genes 
#mito_genes <- gtf[which(gtf$V3 == "rRNA"),]$V9
#mito_genes <- gsub(";.*","", gsub("gene_id ", "", mito_genes))
#paste("These are the mitochondrial genes")
#head(mito_genes)

## extract mito genes
mito_genes <- pb_sex@assays$RNA@counts@Dimnames[[1]][grep("^PBANKA-MIT",pb_sex@assays$RNA@counts@Dimnames[[1]])]

## plot the genes individually
VlnPlot(object = pb_sex, features = mito_genes, pt.size = 0.01)
All cells have the same value of PBANKA-MIT0010.All cells have the same value of PBANKA-MIT0020.All cells have the same value of PBANKA-MIT0030.All cells have the same value of PBANKA-MIT0040.All cells have the same value of PBANKA-MIT0050.All cells have the same value of PBANKA-MIT0090.All cells have the same value of PBANKA-MIT0130.All cells have the same value of PBANKA-MIT0140.All cells have the same value of PBANKA-MIT0150.All cells have the same value of PBANKA-MIT0160.All cells have the same value of PBANKA-MIT0200.All cells have the same value of PBANKA-MIT0210.All cells have the same value of PBANKA-MIT0230.All cells have the same value of PBANKA-MIT0240.All cells have the same value of PBANKA-MIT0250.All cells have the same value of PBANKA-MIT0260.All cells have the same value of PBANKA-MIT0290.All cells have the same value of PBANKA-MIT0300.All cells have the same value of PBANKA-MIT0320.All cells have the same value of PBANKA-MIT0330.All cells have the same value of PBANKA-MIT0340.All cells have the same value of PBANKA-MIT0370.

## make a percentage mitocondrial for each cell (this will work as long as you filter cells out with zero counts)
pb_sex <- PercentageFeatureSet(pb_sex, pattern = "^PBANKA-MIT", col.name = "percent.mt")

plot percentage mitochondrial

## plot for percentage of mitochondrial reads
v1 <- VlnPlot(object = pb_sex, features = "percent.mt", pt.size = 0.01) +
  ## add a line where we will filter
  geom_abline(intercept = 20, col="blue") +
  ## change labels
  labs(x = "",y = "% Mitochondrial Reads", title = "Mitochondrial per cell") +
  ## remove legend
  theme(legend.position = "none") +
  ## change appearance
  theme_classic() +
  scale_fill_manual(values="grey") +
  #scale_y_continuous(limits = c(0, 100)) +
  theme(legend.position="none", axis.text.x = element_blank(), axis.ticks.x=element_blank(), text = element_text(size=20), legend.text=element_text(size=20), axis.text=element_text(size=20), axis.text.y=element_text(colour="black"))

## print
v1


## save
#ggsave("~/images_to_export/QC_10X_mito_violin.png", plot = QC_mito_violin, device = "png", path = NULL, scale = 1, width = 15, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

In the Smart-seq2 data, we use a threshold of 20%. No cell in our 10X data is higher than 13% and only

[1] 10

cells have a % mitochondrial reads above 5%.

nGenes filter

plot individual violin plots

## nGenes plot
gene_plot_5k <- VlnPlot(object = pb_sex, features = "nFeature_RNA", pt.size = 0.01)

## improve the aesthetics
gene_plot_5k <- gene_plot_5k + 
  geom_abline(intercept = 200, col="blue") +
  labs(x = "",y = "nGene", title = "Genes per cell") +
  theme_classic() +
  scale_fill_manual(values="grey") +
  scale_y_continuous(limits = c(0, 3000)) +
  theme(legend.position="none", axis.text.x = element_blank(), axis.ticks.x=element_blank(), text = element_text(size=20), legend.text=element_text(size=20), axis.text=element_text(size=20), axis.text.y=element_text(colour="black"))
Scale for 'y' is already present. Adding another scale for 'y', which will
replace the existing scale.
## nUMI plot
numi_plot_5k <- VlnPlot(object = pb_sex, features = "nCount_RNA", pt.size = 0.01)

## improve aesthetics
numi_plot_5k <- numi_plot_5k +
  labs(x = "",y = "nUMI", title = "UMIs per cell") +
  theme_classic() +
  scale_fill_manual(values="grey") +
  scale_y_continuous(limits = c(0, 3000)) +
  theme(legend.position="none", axis.text.x = element_blank(), axis.ticks.x=element_blank(), text = element_text(size=20), legend.text=element_text(size=20), axis.text=element_text(size=20), axis.text.y=element_text(colour="black"))
Scale for 'y' is already present. Adding another scale for 'y', which will
replace the existing scale.
## plot together
grid.arrange(gene_plot_5k, numi_plot_5k, ncol = 2, top=textGrob("5K cells 10X", gp=gpar(fontsize=15,font=8)))


## save nGene plot on its own
#ggsave("QC_ngene_plot.pdf", plot = gene1, device = "pdf", height = 5, width = 5, units = "in", path = "/Users/ar19/Desktop/PhD/GCSKO_Analysis")

plot two metrics together

## make a dataframe for important filtering metrics
df <- data.frame(nCount = log10(pb_sex@meta.data$nCount_RNA), nGenes = pb_sex@meta.data$nFeature_RNA, percent_mt = pb_sex@meta.data$percent.mt, experiment = pb_sex@meta.data$experiment)

## plot main dotplot
plot1 <- ggplot(df, aes(x = nCount, y = nGenes)) +
  #geom_point(aes(), size = 0.1) +
  geom_hex(bins = 200) +
  #geom_rug() + 
  scale_y_continuous(name = "Number of Detected Genes") + 
  scale_x_continuous(name = "log10(Number of Total UMI)") + 
  theme_pubr() +
  theme(legend.position = "bottom") +
  geom_hline(yintercept=200)

## plot density plot x
dens <- density(df$nCount)
dt <- data.frame(x=dens$x, y=dens$y)
probs <- c(0, 0.25, 0.5, 0.75, 1)
quantiles <- quantile(df$nCount, prob=probs)
dt$quant <- factor(findInterval(dt$x,quantiles))
dens1 <- ggplot(dt, aes(x,y)) + geom_line() + geom_ribbon(aes(ymin=0, ymax=y, fill=quant)) + scale_x_continuous(breaks=quantiles) + scale_fill_brewer(guide="none") + theme_void() + theme(legend.position = "none")
## plot density plot y
## old method
# dens2 <- ggplot(df, aes(x = nGenes, y = experiment)) +
#   geom_density(alpha = 0.2) +
#   theme_void() +
#   theme(legend.position = "none") +
#   coord_flip()
## new method
dens <- density(df$nGenes)
dt <- data.frame(x=dens$x, y=dens$y)
probs <- c(0, 0.25, 0.5, 0.75, 1)
quantiles <- quantile(df$nGenes, prob=probs)
dt$quant <- factor(findInterval(dt$x,quantiles))
dens2 <- ggplot(dt, aes(x,y)) + geom_line() + geom_ribbon(aes(ymin=0, ymax=y, fill=quant)) + scale_x_continuous(breaks=quantiles) + scale_fill_brewer(guide="none") + theme_void() + theme(legend.position = "none") +
  coord_flip()

## plot together
QC_composite_plot <- dens1 + plot_spacer() + plot1 + dens2 + plot_layout(ncol = 2, nrow = 2, widths = c(4, 1), heights = c(1, 4))

## print
QC_composite_plot


## save
<<<<<<< HEAD
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_10X_composite_plot.png", plot = QC_composite_plot, device = "png", path = NULL, scale = 1, width = 15, height = 15, units = "cm", dpi = 300, limitsize = TRUE)
======= ggsave("../images_to_export/QC_10X_composite_plot.png", plot = QC_composite_plot, device = "png", path = NULL, scale = 1, width = 20, height = 20, units = "cm", dpi = 300, limitsize = TRUE) >>>>>>> directory_change

Filtering

The threshold used in the malaria cell atlas was 230 for Pb but this is dependent on sequencing depth etc. We can plot the number of cells recovered for a range of thresholds:

paste("original number of cells =", nrow(pb_sex@meta.data))
[1] "original number of cells = 7762"
paste("with >150 filter =", nrow(pb_sex@meta.data[pb_sex@meta.data$nFeature_RNA > 150, ]))
[1] "with >150 filter = 7188"
paste("with >200 filter =", nrow(pb_sex@meta.data[pb_sex@meta.data$nFeature_RNA > 200, ]))
[1] "with >200 filter = 6631"
paste("with >230 filter =", nrow(pb_sex@meta.data[pb_sex@meta.data$nFeature_RNA > 230, ]))
[1] "with >230 filter = 6239"

Since we have already filtered on nUMI, we will filter with 200.

## number of cells before filtering
pb_sex_pre_filter_nCells <- nrow(pb_sex@meta.data)
## filter object
pb_sex <- subset(pb_sex, subset = nFeature_RNA > 200)
## number of cells after filtering
pb_sex_post_filter_nCells <- nrow(pb_sex@meta.data)
## print results of filtering
paste("number of cells pre-filter", pb_sex_pre_filter_nCells)
[1] "number of cells pre-filter 7762"
paste("number of cells post-filter", pb_sex_post_filter_nCells)
[1] "number of cells post-filter 6631"
paste((pb_sex_pre_filter_nCells - pb_sex_post_filter_nCells), "cells were removed by filtering on number of genes.")
[1] "1131 cells were removed by filtering on number of genes."

5. Dimensionality Reduction and Clustering

Prepare data

## normalise object
pb_sex <- NormalizeData(pb_sex, normalization.method = "LogNormalize", scale.factor = 10000)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
## find variable genes
pb_sex <- FindVariableFeatures(pb_sex, selection.method = "vst", nfeatures = 2000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
## scale the data
all.genes <- rownames(pb_sex)
pb_sex <- ScaleData(pb_sex, features = all.genes)
Centering and scaling data matrix

  |                                                                              
  |                                                                        |   0%
  |                                                                              
  |============                                                            |  17%
  |                                                                              
  |========================                                                |  33%
  |                                                                              
  |====================================                                    |  50%
  |                                                                              
  |================================================                        |  67%
  |                                                                              
  |============================================================            |  83%
  |                                                                              
  |========================================================================| 100%

PCA

## run PCA
pb_sex <- RunPCA(pb_sex, features = VariableFeatures(object = pb_sex))
PC_ 1 
Positive:  PBANKA-1235600, PBANKA-0931300, PBANKA-1214300, PBANKA-1400400, PBANKA-1101100, PBANKA-0205000, PBANKA-0311800, PBANKA-0823400, PBANKA-1242300, PBANKA-1246600 
       PBANKA-0722600, PBANKA-1008500, PBANKA-1308600, PBANKA-0932400, PBANKA-1314800, PBANKA-1300096, PBANKA-1309900, PBANKA-1200096, PBANKA-1145400, PBANKA-0722801 
       PBANKA-1100441, PBANKA-1040521, PBANKA-1326400, PBANKA-1101300, PBANKA-0941300, PBANKA-1210200, PBANKA-1303800, PBANKA-0216061, PBANKA-0406500, PBANKA-1127000 
Negative:  PBANKA-1312700, PBANKA-1224900, PBANKA-0824400, PBANKA-1453000, PBANKA-1115200, PBANKA-1432200, PBANKA-1204200, PBANKA-0703500, PBANKA-0702000, PBANKA-0812600 
       PBANKA-0312700, PBANKA-1128800, PBANKA-1218300, PBANKA-1106500, PBANKA-1430600, PBANKA-1449300, PBANKA-0209300, PBANKA-1232600, PBANKA-1432400, PBANKA-1421500 
       PBANKA-1320800, PBANKA-0620400, PBANKA-1038800, PBANKA-1110700, PBANKA-1336200, PBANKA-0417600, PBANKA-1451100, PBANKA-1143800, PBANKA-1414500, PBANKA-0402700 
PC_ 2 
Positive:  PBANKA-1431500, PBANKA-1431400, PBANKA-0942400, PBANKA-1340400, PBANKA-0934700, PBANKA-1038700, PBANKA-0942300, PBANKA-1449000, PBANKA-1208800, PBANKA-0828900 
       PBANKA-0911000, PBANKA-0306100, PBANKA-0927700, PBANKA-0806800, PBANKA-0416100, PBANKA-0507800, PBANKA-1409600, PBANKA-0411300, PBANKA-0406200, PBANKA-0415800 
       PBANKA-1033700, PBANKA-1361500, PBANKA-0925400, PBANKA-0615200, PBANKA-1108800, PBANKA-0507300, PBANKA-0720100, PBANKA-0920700, PBANKA-1030400, PBANKA-0510600 
Negative:  PBANKA-1317200, PBANKA-1352500, PBANKA-0810700, PBANKA-1225500, PBANKA-1319500, PBANKA-0402500, PBANKA-0827400, PBANKA-1419300, PBANKA-0714000, PBANKA-1315300 
       PBANKA-0105100, PBANKA-1436300, PBANKA-1311400, PBANKA-0417600, PBANKA-0821400, PBANKA-0417200, PBANKA-0204500, PBANKA-1342300, PBANKA-0704900, PBANKA-1415200 
       PBANKA-0605800, PBANKA-1115000, PBANKA-0517600, PBANKA-1329900, PBANKA-1134900, PBANKA-1231300, PBANKA-1233600, PBANKA-1035200, PBANKA-0912500, PBANKA-1363600 
PC_ 3 
Positive:  PBANKA-1400600, PBANKA-1459300, PBANKA-0416000, PBANKA-0304800, PBANKA-0305100, PBANKA-1365200, PBANKA-1443300, PBANKA-0830200, PBANKA-0938400, PBANKA-0827200 
       PBANKA-1137800, PBANKA-1437300, PBANKA-0932200, PBANKA-0506100, PBANKA-1349000, PBANKA-0313800, PBANKA-1113300, PBANKA-0409800, PBANKA-1017100, PBANKA-1117000 
       PBANKA-0408500, PBANKA-1450300, PBANKA-0922500, PBANKA-0934300, PBANKA-0505200, PBANKA-0941800, PBANKA-0915200, PBANKA-0722921, PBANKA-0316600, PBANKA-0519400 
Negative:  PBANKA-1431500, PBANKA-1431400, PBANKA-1449000, PBANKA-0806800, PBANKA-0927700, PBANKA-0911000, PBANKA-1108000, PBANKA-0828900, PBANKA-0601200, PBANKA-1208800 
       PBANKA-1409600, PBANKA-0830900, PBANKA-0942400, PBANKA-1029400, PBANKA-1038700, PBANKA-0102700, PBANKA-1316500, PBANKA-1304500, PBANKA-0521200, PBANKA-1333100 
       PBANKA-0902400, PBANKA-1129600, PBANKA-1119800, PBANKA-0822900, PBANKA-1109600, PBANKA-0301800, PBANKA-1429100, PBANKA-0622000, PBANKA-1038200, PBANKA-0942300 
PC_ 4 
Positive:  PBANKA-0107300, PBANKA-1214300, PBANKA-0814200, PBANKA-0713300, PBANKA-0604300, PBANKA-0405200, PBANKA-0109100, PBANKA-0932200, PBANKA-0823400, PBANKA-1460400 
       PBANKA-1448000, PBANKA-0416500, PBANKA-0938400, PBANKA-0406500, PBANKA-1302800, PBANKA-1130500, PBANKA-1437300, PBANKA-1444100, PBANKA-0211500, PBANKA-1419100 
       PBANKA-0710100, PBANKA-1223100, PBANKA-1235600, PBANKA-1450300, PBANKA-0919600, PBANKA-0916200, PBANKA-1242300, PBANKA-1326400, PBANKA-0313800, PBANKA-0818900 
Negative:  PBANKA-0519000, PBANKA-0519100, PBANKA-0519300, PBANKA-0831000, PBANKA-1349100, PBANKA-1344400, PBANKA-1002400, PBANKA-0713100, PBANKA-0523700, PBANKA-0111000 
       PBANKA-0519400, PBANKA-1349000, PBANKA-1032100, PBANKA-1014500, PBANKA-0932000, PBANKA-0804500, PBANKA-1315700, PBANKA-0501400, PBANKA-1425900, PBANKA-0519200 
       PBANKA-1101400, PBANKA-0509600, PBANKA-0619700, PBANKA-1035400, PBANKA-0417800, PBANKA-1210600, PBANKA-1327100, PBANKA-0523800, PBANKA-0307500, PBANKA-1117200 
PC_ 5 
Positive:  PBANKA-0501600, PBANKA-1240600, PBANKA-1002600, PBANKA-0707700, PBANKA-0112200, PBANKA-1002400, PBANKA-0208900, PBANKA-0307500, PBANKA-0812200, PBANKA-1423000 
       PBANKA-0832800, PBANKA-1119600, PBANKA-1409200, PBANKA-0716900, PBANKA-0100400, PBANKA-1364400, PBANKA-1347000, PBANKA-0915000, PBANKA-0819600, PBANKA-1319000 
       PBANKA-1212500, PBANKA-1400091, PBANKA-0900900, PBANKA-1202000, PBANKA-1345900, PBANKA-0311500, PBANKA-1008600, PBANKA-0911700, PBANKA-1349100, PBANKA-0519200 
Negative:  PBANKA-1443300, PBANKA-0925600, PBANKA-0306700, PBANKA-1106500, PBANKA-0907200, PBANKA-0304800, PBANKA-1217400, PBANKA-1107600, PBANKA-1349000, PBANKA-1319300 
       PBANKA-1313100, PBANKA-0312500, PBANKA-0611700, PBANKA-1113300, PBANKA-0208000, PBANKA-1241800, PBANKA-0305100, PBANKA-1438000, PBANKA-1339300, PBANKA-0304400 
       PBANKA-0833300, PBANKA-0206300, PBANKA-0207500, PBANKA-0519400, PBANKA-0715300, PBANKA-1360000, PBANKA-0112100, PBANKA-1340500, PBANKA-0915200, PBANKA-1416800 
## plot 
DimPlot(pb_sex, reduction = "pca")


## elbow plot
ElbowPlot(pb_sex, ndims = 30, reduction = "pca")

UMAP

## run UMAP
pb_sex <- RunUMAP(pb_sex, dims = 1:10, seed.use = 1234, n.neighbors = 150)
20:34:58 UMAP embedding parameters a = 0.9922 b = 1.112
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
20:34:58 Read 6631 rows and found 10 numeric columns
20:34:58 Using Annoy for neighbor search, n_neighbors = 150
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
20:34:58 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
20:35:00 Writing NN index file to temp file /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//RtmpXGhNV1/file433740c39e54
20:35:00 Searching Annoy index using 1 thread, search_k = 15000
20:35:10 Annoy recall = 100%
20:35:11 Commencing smooth kNN distance calibration using 1 thread
20:35:15 Initializing from normalized Laplacian + noise
20:35:18 Commencing optimization for 500 epochs, with 1163176 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
20:35:34 Optimization finished
## plot
DimPlot(pb_sex, reduction = "umap", group.by = "ident", label = TRUE)


## These are the parameters used in the merge UMAP
#pb_sex <- RunUMAP(pb_sex, reduction = "pca", dims = 1:10, n.neighbors = 150, seed.use = 1234, min.dist = 0.4, repulsion.strength = 0.03, local.connectivity = 150)
#DimPlot(pb_sex, reduction = "umap", group.by = "ident", label = TRUE)

colour with a few marker genes:

# PBANKA-0515000 - p25 - female
# PBANKA-1212600 - HAP2 - male
# PBANKA-0600600 - NEK3 - male
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1315700 - RON2 - (asexuals and some male?)
# PBANKA-0416100 - dynenin heavy chain - male - used in 820 line
# PBANKA-1319500 - CCP2 - female - used in 820 line 
# PBANKA-1437500 - AP2-G - seuxal commitment gene
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)

FeaturePlot(pb_sex, features = c("PBANKA-0515000", "PBANKA-1212600","PBANKA-0600600", "PBANKA-0831000", "PBANKA-1315700", "PBANKA-0416100", "PBANKA-1319500", "PBANKA-1437500", "PBANKA-1102200"))

Clustering

pb_sex <- FindNeighbors(pb_sex, dims = 1:21)
Computing nearest neighbor graph
Computing SNN
pb_sex <- FindClusters(pb_sex, resolution = 1)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 6631
Number of edges: 277150

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8104
Number of communities: 14
Elapsed time: 1 seconds

6. Remove Doublets

DoubletFinder

DoubletFinder function

## DoubletFinder should be able to be installed and run as so:
#devtools::install_github('chris-mcginnis-ucsf/DoubletFinder')
#library(doubletFinder) #allows removal of doublets
## but there seems to be some problems with this so we will run it from the github code

## the doublet finder function
doubletFinder_v3 <- function(seu, PCs, pN = 0.25, pK, nExp, reuse.pANN = FALSE, sct = FALSE) {
  require(Seurat); require(fields); require(KernSmooth)

  ## Generate new list of doublet classificatons from existing pANN vector to save time
  if (reuse.pANN != FALSE ) {
    pANN.old <- seu@meta.data[ , reuse.pANN]
    classifications <- rep("Singlet", length(pANN.old))
    classifications[order(pANN.old, decreasing=TRUE)[1:nExp]] <- "Doublet"
    seu@meta.data[, paste("DF.classifications",pN,pK,nExp,sep="_")] <- classifications
    return(seu)
  }

  if (reuse.pANN == FALSE) {
    ## Make merged real-artifical data
    real.cells <- rownames(seu@meta.data)
    data <- seu@assays$RNA@counts[, real.cells]
    n_real.cells <- length(real.cells)
    n_doublets <- round(n_real.cells/(1 - pN) - n_real.cells)
    print(paste("Creating",n_doublets,"artificial doublets...",sep=" "))
    real.cells1 <- sample(real.cells, n_doublets, replace = TRUE)
    real.cells2 <- sample(real.cells, n_doublets, replace = TRUE)
    doublets <- (data[, real.cells1] + data[, real.cells2])/2
    colnames(doublets) <- paste("X", 1:n_doublets, sep = "")
    data_wdoublets <- cbind(data, doublets)

    ## Store important pre-processing information
    orig.commands <- seu@commands

    ## Pre-process Seurat object
    if (sct == FALSE) {
      print("Creating Seurat object...")
      seu_wdoublets <- CreateSeuratObject(counts = data_wdoublets)

      print("Normalizing Seurat object...")
      seu_wdoublets <- NormalizeData(seu_wdoublets,
                                     normalization.method = orig.commands$NormalizeData.RNA@params$normalization.method,
                                     scale.factor = orig.commands$NormalizeData.RNA@params$scale.factor,
                                     margin = orig.commands$NormalizeData.RNA@params$margin)

      print("Finding variable genes...")
      seu_wdoublets <- FindVariableFeatures(seu_wdoublets,
                                            selection.method = orig.commands$FindVariableFeatures.RNA$selection.method,
                                            loess.span = orig.commands$FindVariableFeatures.RNA$loess.span,
                                            clip.max = orig.commands$FindVariableFeatures.RNA$clip.max,
                                            mean.function = orig.commands$FindVariableFeatures.RNA$mean.function,
                                            dispersion.function = orig.commands$FindVariableFeatures.RNA$dispersion.function,
                                            num.bin = orig.commands$FindVariableFeatures.RNA$num.bin,
                                            binning.method = orig.commands$FindVariableFeatures.RNA$binning.method,
                                            nfeatures = orig.commands$FindVariableFeatures.RNA$nfeatures,
                                            mean.cutoff = orig.commands$FindVariableFeatures.RNA$mean.cutoff,
                                            dispersion.cutoff = orig.commands$FindVariableFeatures.RNA$dispersion.cutoff)

      print("Scaling data...")
      seu_wdoublets <- ScaleData(seu_wdoublets,
                                 features = orig.commands$ScaleData.RNA$features,
                                 model.use = orig.commands$ScaleData.RNA$model.use,
                                 do.scale = orig.commands$ScaleData.RNA$do.scale,
                                 do.center = orig.commands$ScaleData.RNA$do.center,
                                 scale.max = orig.commands$ScaleData.RNA$scale.max,
                                 block.size = orig.commands$ScaleData.RNA$block.size,
                                 min.cells.to.block = orig.commands$ScaleData.RNA$min.cells.to.block)

      print("Running PCA...")
      seu_wdoublets <- RunPCA(seu_wdoublets,
                              features = orig.commands$ScaleData.RNA$features,
                              npcs = length(PCs),
                              rev.pca =  orig.commands$RunPCA.RNA$rev.pca,
                              weight.by.var = orig.commands$RunPCA.RNA$weight.by.var,
                              verbose=FALSE)
      pca.coord <- seu_wdoublets@reductions$pca@cell.embeddings[ , PCs]
      cell.names <- rownames(seu_wdoublets@meta.data)
      nCells <- length(cell.names)
      rm(seu_wdoublets); gc() # Free up memory
    }

    if (sct == TRUE) {
      require(sctransform)
      print("Creating Seurat object...")
      seu_wdoublets <- CreateSeuratObject(counts = data_wdoublets)

      print("Running SCTransform...")
      seu_wdoublets <- SCTransform(seu_wdoublets)

      print("Running PCA...")
      seu_wdoublets <- RunPCA(seu_wdoublets, npcs = length(PCs))
      pca.coord <- seu_wdoublets@reductions$pca@cell.embeddings[ , PCs]
      cell.names <- rownames(seu_wdoublets@meta.data)
      nCells <- length(cell.names)
      rm(seu_wdoublets); gc()
    }

    ## Compute PC distance matrix
    print("Calculating PC distance matrix...")
    dist.mat <- fields::rdist(pca.coord)

    ## Compute pANN
    print("Computing pANN...")
    pANN <- as.data.frame(matrix(0L, nrow = n_real.cells, ncol = 1))
    rownames(pANN) <- real.cells
    colnames(pANN) <- "pANN"
    k <- round(nCells * pK)
    for (i in 1:n_real.cells) {
      neighbors <- order(dist.mat[, i])
      neighbors <- neighbors[2:(k + 1)]
      neighbor.names <- rownames(dist.mat)[neighbors]
      pANN$pANN[i] <- length(which(neighbors > n_real.cells))/k
    }

    print("Classifying doublets..")
    classifications <- rep("Singlet",n_real.cells)
    classifications[order(pANN$pANN[1:n_real.cells], decreasing=TRUE)[1:nExp]] <- "Doublet"
    seu@meta.data[, paste("pANN",pN,pK,nExp,sep="_")] <- pANN[rownames(seu@meta.data), 1]
    seu@meta.data[, paste("DF.classifications",pN,pK,nExp,sep="_")] <- classifications
    return(seu)
  }
}
## usage: https://rdrr.io/github/chris-mcginnis-ucsf/DoubletFinder/man/doubletFinder_v3.html
## source: https://github.com/chris-mcginnis-ucsf/DoubletFinder/blob/master/R/doubletFinder_v3.R

Run DoubletFinder

# the tutorial recommends using this as an approximation:
#nExp_poi <- round(0.15*nrow(pb_sex@meta.data))
#but a more appropriate approximation is that the expected number of doublets is ~1% per 1000 cells so:
nExp_poi <- round((0.01*(nrow(pb_sex@meta.data)/1000))*nrow(pb_sex@meta.data))
#run doublet finder:
pb_sex <- doubletFinder_v3(pb_sex, PCs = 1:21, pN = 0.25, pK = 0.01, nExp = nExp_poi, reuse.pANN = FALSE, sct = FALSE)
[1] "Creating 2210 artificial doublets..."
[1] "Creating Seurat object..."
[1] "Normalizing Seurat object..."
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
[1] "Finding variable genes..."
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
[1] "Scaling data..."
Centering and scaling data matrix

  |                                                                              
  |                                                                        |   0%
  |                                                                              
  |============                                                            |  17%
  |                                                                              
  |========================                                                |  33%
  |                                                                              
  |====================================                                    |  50%
  |                                                                              
  |================================================                        |  67%
  |                                                                              
  |============================================================            |  83%
  |                                                                              
  |========================================================================| 100%
[1] "Running PCA..."
[1] "Calculating PC distance matrix..."
[1] "Computing pANN..."
[1] "Classifying doublets.."

results in:

table(pb_sex@meta.data$DF.classifications_0.25_0.01_440)

Doublet Singlet 
    440    6191 

Validation and visualisation of doublets

visualise where doublets are:

doublet.cells <- c(rownames(pb_sex@meta.data[pb_sex@meta.data$DF.classifications_0.25_0.01_440 == "Doublet",]))
d1 <- DimPlot(pb_sex, reduction = "umap", cells.highlight = doublet.cells, sizes.highlight = 2)
#TSNEPlot(object = pb_sex, cells.highlight = doublet.cells, do.return = TRUE, )
doublet1 <- d1 + coord_fixed() + theme(axis.text.x=element_blank())

## plot clusters
cluster_plot <- DimPlot(pb_sex, reduction = "umap", group.by = "ident", label = TRUE)

doublet1 + cluster_plot

VlnPlot(object = pb_sex, features = "pANN_0.25_0.01_440", pt.size = 0.1)

## extract meta data cols of interest
df <- pb_sex@meta.data[,c("RNA_snn_res.1","DF.classifications_0.25_0.01_440")]

## make a table from doublets
df <- data.frame(rbind(table(df)))

## ammend rownames
df$cluster <- rownames(df)

## calculate percentages of cells that are doublets
df$pc_doublet <- ((df[,1])/((df[,1]) + df[,2]))*100

## inspect
#kable(df[order(df$pc_doublet),])

## plot 
ggplot(data=df, aes(x=cluster, y=pc_doublet)) +
  geom_col(fill="steelblue") +
  theme_minimal()

Filter doublets

It definitely seems like there are some biases in doublet detection. Fewer doublets in very early rings and in mature sexes may be due to a smaller number of the population being these cells.

It may also be biological, that these cells are less likely to associate to one another (although less likely, as doublets are a result of the probability of two cells being captured inside the same droplet together at a certain loading concentration, rather than two cells already being together upon droplet capture).

remove doublets:

## make a list of singlet cells
keep_singlets <- rownames(pb_sex@meta.data[pb_sex@meta.data$DF.classifications_0.25_0.01_440 == "Singlet",])

## subset into new seurat object
pb_sex_filtered <- subset(pb_sex, cells = keep_singlets, subset.raw = TRUE)
The following arguments are not used: subset.raw
## compare old and new objects
pb_sex
An object of class Seurat 
5098 features across 6631 samples within 1 assay 
Active assay: RNA (5098 features, 2000 variable features)
 2 dimensional reductions calculated: pca, umap
pb_sex_filtered
An object of class Seurat 
5098 features across 6191 samples within 1 assay 
Active assay: RNA (5098 features, 2000 variable features)
 2 dimensional reductions calculated: pca, umap

7. Life Cycle Stage (Using Bulk RNA-Seq Correlation)

Add in bulk data predictions

hoo et al.

#Pb Prediction correlations with bulk data (asexual hoo): 

#Load in required package:
library(Hmisc)
#Cooerce expression data into a matrix and load in the reference timecourse data:
x10 <- as.matrix(pb_sex_filtered@assays$RNA@data)
rownames(x10) <- gsub("-", "_", rownames(x10))
#read in bulk data:
hoo<-as.matrix(read.table("../data/Reference/hoo_berg2.txt",header=T, row.names=1))
#Make a blank dataframe in which to add prediction:
df <- data.frame(matrix(ncol = 4, nrow = 0))
colnames(df) <- c("Prediction(Spearman)","r(Spearman)","Prediction(Pearsons)","r(Pearsons)")
#Do correlations with bulk data using both Spearman and Pearson (and the top 1000 genes):
for (i in 1:ncol(x10))
{
  shared<-intersect(row.names(as.matrix(head(sort(x10[,i], decreasing=TRUE),1000))),row.names(hoo))
  step0<-rcorr(x10[shared,i],hoo[shared,1:12],type = "spearman")
  step1<-as.matrix(t(step0$r[2:13,1]))
  step2<-rcorr(x10[shared,i],hoo[shared,1:12],type = "pearson")
  step3<-as.matrix(t(step2$r[2:13,1]))
  step4<-cbind(colnames(step1)[which.max(step1)],step1[which.max(step1)],colnames(step3)[which.max(step3)],step3[which.max(step3)])
  colnames(step4) <- c("Prediction(Spearman)","r(Spearman)","Prediction(Pearsons)","r(Pearsons)")
  rownames(step4)<-colnames(x10)[i]
  df<-rbind(df,step4)
}
#Write out data into a csv file:
#write.csv(dfringr,file="/Users/ar19/Desktop/PhD/AR04_GCSKO_project/All_mutants_Feb_2018/predictionpbcombined.csv")
#Change the format of the output to make it more readable:
#gsub("Pb_","", dfringr[,1]) - Make predictions into 18hr.dat format:

#spearman:
df[,1] <- gsub("Pb_","", df[,1])
#Remove hr.dat from list:
df[,1] <- gsub("hr.dat","", df[,1])
#Check - dfringr[,1]
#Make into a number:
df[,1] <- as.numeric(df[,1])
df[,2] <- as.numeric(as.character(df[,2]))

#pearson:
df[,3] <- gsub("Pb_","", df[,3])
#Remove hr.dat from list:
df[,3] <- gsub("hr.dat","", df[,3])
#Check - dfringr[,1]
#Make into a number:
df[,3] <- as.numeric(df[,3])
df[,4] <- as.numeric(as.character(df[,4]))
#add to 10X object:
pb_sex_filtered <- AddMetaData(pb_sex_filtered, metadata = df)
Invalid name supplied, making object name syntactically valid. New object name is Prediction.Spearman.r.Spearman.Prediction.Pearsons.r.Pearsons.; see ?make.names for more details on syntax validity

Kasia’s data

Can also do with Kasia’s timecourse data:

kas<-as.matrix(read.table("../data/Reference/AP2OETC.txt",header=T, row.names=1))
#Make a blank dataframe in which to add prediction:
dfs <- data.frame(matrix(ncol = 4, nrow = 0))
colnames(dfs) <- c("ID","Prediction","r (Pearson)")
#Do correlations with bulk data using both Spearman and Pearson (and the top 1000 genes):
for (i in 1:ncol(x10))
{
  shared<-intersect(row.names(as.matrix(head(sort(x10[,i], decreasing=TRUE),1000))),rownames(kas))
  step0<-rcorr(x10[shared,i],kas[shared,1:10],type = "spearman")
  step1<-as.matrix(t(step0$r[2:11,1]))
  step2<-rcorr(x10[shared,i],kas[shared,1:10],type = "pearson")
  step3<-as.matrix(t(step2$r[2:11,1]))
  step4<-cbind(colnames(step1)[which.max(step1)],step1[which.max(step1)],colnames(step3)[which.max(step3)],step3[which.max(step3)])
  colnames(step4) <- c("Prediction(Spearman)","r(Spearman)","Prediction(Pearsons)","r(Pearsons)")
  rownames(step4)<-colnames(x10)[i]
  dfs<-rbind(dfs,step4)
}
#Write out data into a csv file:
#write.csv(df,file="/Users/ar19/Desktop/PhD/AR04_GCSKO_project/All_mutants_Feb_2018/predictionkasiacombined.csv")

#Change the format of the output to make it more readable:
#gsub("Pb_","", dfs[,1]) - Make predictions into 18hr.dat format:
dfs[,1] <- gsub("X","", dfs[,1])
#Make into a number:
dfs[,1] <- as.numeric(dfs[,1])
#Make into a number:
dfs[,2] <- as.numeric(as.character(dfs[,2]))

#gsub("Pb_","", dfs[,1]) - Make predictions into 18hr.dat format:
dfs[,3] <- gsub("X","", dfs[,3])
#Make into a number:
dfs[,3] <- as.numeric(dfs[,3])
#dfs[,1]
#Make into a number:
dfs[,4] <- as.numeric(as.character(dfs[,4]))

colnames(dfs) <- c('Prediction(Spearman)_Kasia', 'r(Spearman)_Kasia', 'Prediction(Pearson)_Kasia', 'r(Pearson)_Kasia')
#add to Seurat:
#add to 10X object:
pb_sex_filtered <- AddMetaData(pb_sex_filtered, dfs)
Invalid name supplied, making object name syntactically valid. New object name is Prediction.Spearman._Kasiar.Spearman._KasiaPrediction.Pearson._Kasiar.Pearson._Kasia; see ?make.names for more details on syntax validity

Visualise

Confirm life cycle designations:

## plot
FeaturePlot(pb_sex_filtered, features = c("Prediction.Spearman._Kasia", "Prediction.Spearman."))

optimse UMAP

## PCA calc
pb_sex_filtered <- RunPCA(pb_sex_filtered, features = VariableFeatures(object = pb_sex_filtered))
The following 5 features requested have zero variance (running reduction without them): PBANKA-0612861, PBANKA-0836921, PBANKA-1000041, PBANKA-API0290, PBANKA-API0031PC_ 1 
Positive:  PBANKA-1235600, PBANKA-0931300, PBANKA-1214300, PBANKA-1400400, PBANKA-1101100, PBANKA-0205000, PBANKA-0311800, PBANKA-0823400, PBANKA-1242300, PBANKA-1246600 
       PBANKA-0722600, PBANKA-1008500, PBANKA-0932400, PBANKA-1308600, PBANKA-1314800, PBANKA-1309900, PBANKA-1300096, PBANKA-1145400, PBANKA-1200096, PBANKA-1100441 
       PBANKA-0722801, PBANKA-1101300, PBANKA-1326400, PBANKA-1040521, PBANKA-0941300, PBANKA-1127000, PBANKA-1303800, PBANKA-0406500, PBANKA-1210200, PBANKA-0814200 
Negative:  PBANKA-1312700, PBANKA-1224900, PBANKA-0824400, PBANKA-1115200, PBANKA-1453000, PBANKA-1432200, PBANKA-1204200, PBANKA-0703500, PBANKA-0702000, PBANKA-0812600 
       PBANKA-0312700, PBANKA-1128800, PBANKA-1218300, PBANKA-1232600, PBANKA-1432400, PBANKA-1430600, PBANKA-1449300, PBANKA-1106500, PBANKA-0209300, PBANKA-0620400 
       PBANKA-1421500, PBANKA-1336200, PBANKA-1320800, PBANKA-0417600, PBANKA-1038800, PBANKA-1129800, PBANKA-1414500, PBANKA-1451100, PBANKA-1143800, PBANKA-0402700 
PC_ 2 
Positive:  PBANKA-1431500, PBANKA-1431400, PBANKA-0942400, PBANKA-1340400, PBANKA-1449000, PBANKA-1038700, PBANKA-0942300, PBANKA-0934700, PBANKA-1208800, PBANKA-0828900 
       PBANKA-0911000, PBANKA-0306100, PBANKA-0927700, PBANKA-0806800, PBANKA-1409600, PBANKA-0406200, PBANKA-0411300, PBANKA-0415800, PBANKA-0507800, PBANKA-0416100 
       PBANKA-1033700, PBANKA-1361500, PBANKA-1108800, PBANKA-0920700, PBANKA-0510600, PBANKA-0925400, PBANKA-0720100, PBANKA-0507300, PBANKA-1119800, PBANKA-1030400 
Negative:  PBANKA-1317200, PBANKA-1352500, PBANKA-0827400, PBANKA-0810700, PBANKA-1225500, PBANKA-1319500, PBANKA-0402500, PBANKA-1419300, PBANKA-0714000, PBANKA-1315300 
       PBANKA-1436300, PBANKA-0105100, PBANKA-1311400, PBANKA-0821400, PBANKA-0417600, PBANKA-0204500, PBANKA-1342300, PBANKA-0417200, PBANKA-0605800, PBANKA-0704900 
       PBANKA-0517600, PBANKA-1231300, PBANKA-1329900, PBANKA-1415200, PBANKA-1115000, PBANKA-1134900, PBANKA-1035200, PBANKA-1233600, PBANKA-0907100, PBANKA-0912500 
PC_ 3 
Positive:  PBANKA-1400600, PBANKA-1459300, PBANKA-0416000, PBANKA-0305100, PBANKA-0304800, PBANKA-1443300, PBANKA-1365200, PBANKA-0830200, PBANKA-0938400, PBANKA-1349000 
       PBANKA-0827200, PBANKA-1137800, PBANKA-1437300, PBANKA-1113300, PBANKA-0932200, PBANKA-0506100, PBANKA-1017100, PBANKA-0313800, PBANKA-0408500, PBANKA-1117000 
       PBANKA-0409800, PBANKA-0922500, PBANKA-0519400, PBANKA-0925600, PBANKA-0316600, PBANKA-0915200, PBANKA-0722921, PBANKA-0934300, PBANKA-0941800, PBANKA-1225000 
Negative:  PBANKA-1431500, PBANKA-1431400, PBANKA-1449000, PBANKA-0806800, PBANKA-1108000, PBANKA-0927700, PBANKA-0911000, PBANKA-0828900, PBANKA-0601200, PBANKA-1208800 
       PBANKA-1409600, PBANKA-0830900, PBANKA-0521200, PBANKA-1029400, PBANKA-0102700, PBANKA-0942400, PBANKA-1304500, PBANKA-1316500, PBANKA-1038700, PBANKA-1333100 
       PBANKA-0902400, PBANKA-1109600, PBANKA-1129600, PBANKA-1119800, PBANKA-0822900, PBANKA-0719700, PBANKA-1429100, PBANKA-1038200, PBANKA-0301800, PBANKA-1320100 
PC_ 4 
Positive:  PBANKA-0519000, PBANKA-1349100, PBANKA-0519100, PBANKA-0519300, PBANKA-1344400, PBANKA-0831000, PBANKA-1002400, PBANKA-0713100, PBANKA-0523700, PBANKA-0111000 
       PBANKA-1032100, PBANKA-1014500, PBANKA-0519400, PBANKA-0932000, PBANKA-0804500, PBANKA-1349000, PBANKA-1315700, PBANKA-0501400, PBANKA-1101400, PBANKA-1425900 
       PBANKA-0519200, PBANKA-1210600, PBANKA-0509600, PBANKA-0619700, PBANKA-1327100, PBANKA-0523800, PBANKA-0307500, PBANKA-1035400, PBANKA-1119600, PBANKA-1117200 
Negative:  PBANKA-0107300, PBANKA-0814200, PBANKA-1214300, PBANKA-0713300, PBANKA-0604300, PBANKA-0405200, PBANKA-0932200, PBANKA-0109100, PBANKA-0823400, PBANKA-0938400 
       PBANKA-0416500, PBANKA-1460400, PBANKA-1437300, PBANKA-1302800, PBANKA-1130500, PBANKA-0406500, PBANKA-1448000, PBANKA-0211500, PBANKA-1444100, PBANKA-1450300 
       PBANKA-0710100, PBANKA-1223100, PBANKA-1419100, PBANKA-0313800, PBANKA-0818900, PBANKA-0919600, PBANKA-1235600, PBANKA-1242300, PBANKA-0916200, PBANKA-1203700 
PC_ 5 
Positive:  PBANKA-0501600, PBANKA-1240600, PBANKA-0707700, PBANKA-0112200, PBANKA-1002600, PBANKA-0208900, PBANKA-0812200, PBANKA-1423000, PBANKA-0832800, PBANKA-1409200 
       PBANKA-0307500, PBANKA-0716900, PBANKA-0100400, PBANKA-1002400, PBANKA-0915000, PBANKA-1364400, PBANKA-1119600, PBANKA-1347000, PBANKA-0819600, PBANKA-1319000 
       PBANKA-1212500, PBANKA-0900900, PBANKA-1202000, PBANKA-1400091, PBANKA-1228800, PBANKA-0911700, PBANKA-0311500, PBANKA-1345900, PBANKA-1025300, PBANKA-0519200 
Negative:  PBANKA-1443300, PBANKA-0925600, PBANKA-0306700, PBANKA-0907200, PBANKA-1349000, PBANKA-1106500, PBANKA-1217400, PBANKA-1107600, PBANKA-1319300, PBANKA-0304800 
       PBANKA-0519400, PBANKA-0312500, PBANKA-1313100, PBANKA-0305100, PBANKA-0112100, PBANKA-0611700, PBANKA-1241800, PBANKA-0304400, PBANKA-0833300, PBANKA-0208000 
       PBANKA-1113300, PBANKA-1339300, PBANKA-1438000, PBANKA-0206300, PBANKA-1340500, PBANKA-0207500, PBANKA-0915200, PBANKA-0808000, PBANKA-1020100, PBANKA-1360000 
## elbow plot
ElbowPlot(pb_sex_filtered, ndims = 30, reduction = "pca")


## UMAP calc
pb_sex_filtered <- RunUMAP(pb_sex_filtered, dims = 1:8, seed.use = 300, n.neighbors = 60, min.dist = 0.5, repulsion.strength = 0.05, local.connectivity = 20)
20:39:44 UMAP embedding parameters a = 0.583 b = 1.334
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
20:39:44 Read 6191 rows and found 8 numeric columns
20:39:44 Using Annoy for neighbor search, n_neighbors = 60
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
20:39:44 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
20:39:46 Writing NN index file to temp file /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//RtmpXGhNV1/file43376acfbe03
20:39:46 Searching Annoy index using 1 thread, search_k = 6000
20:39:51 Annoy recall = 100%
20:39:53 Commencing smooth kNN distance calibration using 1 thread
20:39:54 6191 smooth knn distance failures
20:39:57 Initializing from normalized Laplacian + noise
20:39:57 Commencing optimization for 500 epochs, with 184004 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
20:40:27 Optimization finished
## UMAP plot
DimPlot(pb_sex_filtered, reduction = "umap", group.by = "ident", label = TRUE)

8. Save and Export

Save environment

## This saves everything in the global environment for easy recall later
#save.image(file = "GCSKO_10X_QC.RData")
#load(file = "GCSKO_10X_QC.RData")

Save object(s)

## save Rdata
#save(pb_30k_sex_filtered, pb_sex_filtered, file = "Part_2_input.Rdata")
#load(file = "Part_2_input.Rdata")

## save RDS
saveRDS(pb_sex_filtered, file = "../data_to_export/pb_sex_filtered.RDS", compress = FALSE) 
#pb_sex_filtered <- readRDS("pb_sex_filtered.RDS")

## Save Robj
#save(pb_sex_filtered,file="pb_sex_filtered.Robj")

Appendix

Session Info

R version 4.0.2 (2020-06-22)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.6

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8

attached base packages:
 [1] stats4    parallel  grid      stats     graphics  grDevices utils    
 [8] datasets  methods   base     

other attached packages:
 [1] SingleCellExperiment_1.10.1 SummarizedExperiment_1.18.2
 [3] DelayedArray_0.14.1         matrixStats_0.56.0         
 [5] GenomicRanges_1.40.0        GenomeInfoDb_1.24.2        
 [7] IRanges_2.22.2              S4Vectors_0.26.1           
 [9] Biobase_2.48.0              BiocGenerics_0.34.0        
[11] KernSmooth_2.23-17          fields_10.3                
[13] maps_3.3.0                  spam_2.5-1                 
[15] dotCall64_1.0-0             mixtools_1.2.0             
[17] scales_1.1.1                knitr_1.29                 
[19] reshape2_1.4.4              Hmisc_4.4-0                
[21] Formula_1.2-3               survival_3.2-3             
[23] lattice_0.20-41             gridExtra_2.3              
[25] dplyr_1.0.0                 patchwork_1.0.1            
[27] ggplot2bdc_0.3.2            cowplot_1.0.0              
[29] ggpubr_0.4.0                ggplot2_3.3.2              
[31] viridis_0.5.1               viridisLite_0.3.0          
[33] Seurat_3.2.0               

loaded via a namespace (and not attached):
  [1] reticulate_1.16        tidyselect_1.1.0       htmlwidgets_1.5.1     
  [4] Rtsne_0.15             devtools_2.3.0         munsell_0.5.0         
  [7] codetools_0.2-16       ica_1.0-2              future_1.18.0         
 [10] miniUI_0.1.1.1         withr_2.2.0            colorspace_1.4-1      
 [13] highr_0.8              rstudioapi_0.11        ROCR_1.0-11           
 [16] ggsignif_0.6.0         tensor_1.5             listenv_0.8.0         
 [19] labeling_0.3           GenomeInfoDbData_1.2.3 polyclip_1.10-0       
 [22] farver_2.0.3           pheatmap_1.0.12        rprojroot_1.3-2       
 [25] vctrs_0.3.2            generics_0.0.2         xfun_0.15             
 [28] R6_2.4.1               rsvd_1.0.3             bitops_1.0-6          
 [31] spatstat.utils_1.17-0  assertthat_0.2.1       promises_1.1.1        
 [34] nnet_7.3-14            gtable_0.3.0           globals_0.12.5        
 [37] processx_3.4.3         goftest_1.2-2          rlang_0.4.7           
 [40] splines_4.0.2          rstatix_0.6.0          lazyeval_0.2.2        
 [43] acepack_1.4.1          hexbin_1.28.1          broom_0.7.0           
 [46] checkmate_2.0.0        yaml_2.2.1             abind_1.4-5           
 [49] crosstalk_1.1.0.1      backports_1.1.8        httpuv_1.5.4          
 [52] tools_4.0.2            usethis_1.6.1          ellipsis_0.3.1        
 [55] RColorBrewer_1.1-2     sessioninfo_1.1.1      ggridges_0.5.2        
 [58] Rcpp_1.0.5             plyr_1.8.6             zlibbioc_1.34.0       
 [61] base64enc_0.1-3        RCurl_1.98-1.2         purrr_0.3.4           
 [64] ps_1.3.3               prettyunits_1.1.1      rpart_4.1-15          
 [67] deldir_0.1-28          pbapply_1.4-2          zoo_1.8-8             
 [70] haven_2.3.1            ggrepel_0.8.2          cluster_2.1.0         
 [73] fs_1.4.2               tinytex_0.25           magrittr_1.5          
 [76] data.table_1.12.8      RSpectra_0.16-0        openxlsx_4.1.5        
 [79] lmtest_0.9-37          RANN_2.6.1             fitdistrplus_1.1-1    
 [82] pkgload_1.1.0          hms_0.5.3              mime_0.9              
 [85] evaluate_0.14          xtable_1.8-4           rio_0.5.16            
 [88] jpeg_0.1-8.1           readxl_1.3.1           testthat_2.3.2        
 [91] compiler_4.0.2         tibble_3.0.3           crayon_1.3.4          
 [94] htmltools_0.5.0        segmented_1.2-0        mgcv_1.8-31           
 [97] later_1.1.0.1          tidyr_1.1.0            MASS_7.3-51.6         
[100] Matrix_1.2-18          car_3.0-8              cli_2.0.2             
[103] igraph_1.2.5           forcats_0.5.0          pkgconfig_2.0.3       
[106] foreign_0.8-80         plotly_4.9.2.1         XVector_0.28.0        
[109] stringr_1.4.0          callr_3.4.3            digest_0.6.25         
[112] sctransform_0.2.1      RcppAnnoy_0.0.16       spatstat.data_1.4-3   
[115] rmarkdown_2.3          cellranger_1.1.0       leiden_0.3.3          
[118] htmlTable_2.0.1        uwot_0.1.8             curl_4.3              
[121] kernlab_0.9-29         shiny_1.5.0            lifecycle_0.2.0       
[124] nlme_3.1-148           jsonlite_1.7.0         carData_3.0-4         
[127] desc_1.2.0             fansi_0.4.1            pillar_1.4.6          
[130] fastmap_1.0.1          httr_1.4.2             pkgbuild_1.1.0        
[133] glue_1.4.1             remotes_2.1.1          zip_2.1.0             
[136] spatstat_1.64-1        png_0.1-7              stringi_1.4.6         
[139] latticeExtra_0.6-29    memoise_1.1.0          irlba_2.3.3           
[142] future.apply_1.6.0     ape_5.4               
LS0tCnN1YnRpdGxlOiAnR2FtZXRvY3l0ZSBEZXZlbG9wbWVudCBpbiA8aT5QbGFzbW9kaXVtIGJlcmdoZWk8L2k+Jwp0aXRsZTogfAogICFbXSgvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvR0NTS09fbG9nby5qcGcpe3dpZHRoPTMwMHB4fSAgCiAgMTBYIFF1YWxpdHkgQ29udHJvbAphdXRob3I6ICJbQW5kcmV3IFJ1c3NlbGxdKGh0dHBzOi8vYWpjcnVzc2VsbC53aXhzaXRlLmNvbS9teXNpdGUvYWJvdXQpIgppbnN0aXR1dGU6IFdlbGxjb21lIFNhbmdlciBJbnN0aXR1dGUKZGF0ZTogJ2ByIGZvcm1hdChTeXMuRGF0ZSgpLCAiJUIgJWQsICVZIilgJwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgI3RvY19mbG9hdDogeWVzCiAgICBkZl9wcmludDogcGFnZWQKLS0tCioqKgojIDEuIEludHJvZHVjdGlvbiBhbmQgQWltcyB7LnRhYnNldH0KClR3byBkYXRhc2V0cyB3ZXJlIGdlbmVyYXRlZCB1c2luZyB0aGUgMTBYIEdlbm9taWNzIENocm9taXVtIDMnIHNjUk5BLVNlcSBwbGF0Zm9ybToKCmBgYHtyIGludHJvLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KIyMgbG9hZCBrbml0ciB0byBkaXNwbGF5IHRhYmxlCmxpYnJhcnkoa25pdHIpCiMjIG1ha2UgZGF0YWZyYW1lCnNwZWNpZXMgPC0gYygicGIiLCAicGIiKQpleHBlcmltZW50X25hbWUgPC0gYygnc3RyYWlnaHQgYmxlZWQgZXhwZXJpbWVudCcsJzE6MSBtaXggZXhwZXJpbWVudCcpCnJ1bl9udW1iZXIgPC0gYygiMjIyNTIiLCAiMjQyODQiKQpsYW5lX251bWJlciA8LSBjKCI1IiwgIjEgJiAyIikKc2VxdWVuY2VyIDwtIGMoIkhpc2VxIDQwMDAiLCAiSGlzZXEgMjUwMCIpCmFwcHJveGltYXRlX251bWJlcl9vZl9jZWxscyA8LSBjKCIzMCwwMDAiLCAiNSwwMDAiKQplbXBsb3kuZGF0YSA8LSBkYXRhLmZyYW1lKHNwZWNpZXMsIGV4cGVyaW1lbnRfbmFtZSwgcnVuX251bWJlciwgbGFuZV9udW1iZXIsIHNlcXVlbmNlciwgYXBwcm94aW1hdGVfbnVtYmVyX29mX2NlbGxzLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQojIyBwcmludCBkYXRhZnJhbWUKa2FibGUoZW1wbG95LmRhdGEpCmBgYAoKVGhpcyBzY3JpcHQgZGV0YWlscyB0aGUgcXVhbGl0eSBjb250cm9sIG9mIHRoZSAxOjEgbWl4IGV4cGVyaW1lbnQKClRoaXMgZGF0YSBoYXMgYmVlbiBwcm9jZXNzZWQgdXNpbmcgQ2VsbFJhbmdlciBpbnRvIGNvdW50cyB0YWJsZXMuIFRoaXMgaW5pdGlhbCBhbmFseXNpcyBnYXZlIHRoZSBmb2xsb3dpbmcgbWV0cmljczoKCjxiPlBiIDE6MSBtaXggZXhwZXJpbWVudCAocnVuICM6IDI0Mjg0IGxhbmVzIDEgYW5kIDIgKEhpc2VxIDI1MDApKTo8L2I+Cgo8ZGl2IHN0eWxlPSJ3aWR0aDo1MDBweDsgaGVpZ2h0OjQwMHB4Ij4hW10oL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2RhdGEvMTBYLzI0Mjg0X2NlbGxyYW5nZXJfb3V0cHV0XzEucG5nKTwvZGl2Pgo8ZGl2IHN0eWxlPSJ3aWR0aDo1MDBweDsgaGVpZ2h0OjIwMHB4Ij4hW10oL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2RhdGEvMTBYLzI0Mjg0X2NlbGxyYW5nZXJfb3V0cHV0XzIucG5nKTwvZGl2PgoKPGI+V2Ugd2lsbCBsb2FkIHRoaXMgZGF0YSBpbiBhbmQgZm9yIGVhY2ggcnVuOjwvYj4KCkEuIERlZmluZSAnY2VsbHMnCgpCLiBGaWx0ZXIgcG9vciBxdWFsaXR5IGNlbGxzIG91dAoKQy4gRGltZW5zaW9uYWxpdHkgUmVkdWN0aW9uIGFuZCBDbHVzdGVyaW5nIAoKRC4gUmVtb3ZlIERvdWJsZXRzCgpFLiBQcmVkaWN0IGxpZmUgQ3ljbGUgU3RhZ2UgKFVzaW5nIEJ1bGsgUk5BLVNlcSBDb3JyZWxhdGlvbikKCiMgMi4gUmVhZCBpbiB0aGUgZGF0YSAgey50YWJzZXR9CgojIyMgTG9hZCB0aGUgcmVxdWlyZWQgcGFja2FnZXMKCmBgYHtyIGxvYWQgcGFja2FnZXMsIGVjaG8gPSBGQUxTRX0KIyMgU2V1cmF0IGlzIG5lZWRlZCBmb3IgbW9zdCBvZiB0aGlzIHNjcmlwdAppZihyZXF1aXJlKCJTZXVyYXQiLCBxdWlldGx5ID0gVFJVRSkpewogICAgcHJpbnQoIlNldXJhdCBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBTZXVyYXQiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiU2V1cmF0IikKICAgIGlmKHJlcXVpcmUoU2V1cmF0KSl7CiAgICAgICAgcHJpbnQoIlNldXJhdCBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIFNldXJhdCIpCiAgICB9Cn0KCiMjIGNvd3Bsb3QgaXMgbmVlZGVkIGZvciBwbG90cwppZihyZXF1aXJlKCJjb3dwbG90IikpewogICAgcHJpbnQoImNvd3Bsb3QgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgY293cGxvdCIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJjb3dwbG90IikKICAgIGlmKHJlcXVpcmUoY293cGxvdCkpewogICAgICAgIHByaW50KCJjb3dwbG90IGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgY293cGxvdCIpCiAgICB9Cn0KCiMjIGdyaWRFeHRyYSBpcyBuZWVkZWQgZm9yIGdyaWQgZ3JhcGhpY3MgdG8gcGxvdCBtdWx0aXBsZSBwbG90cyBpbiB0aGUgc2FtZSB2aWV3CmlmKHJlcXVpcmUoImdyaWRFeHRyYSIpKXsKICAgIHByaW50KCJncmlkRXh0cmEgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgZ3JpZEV4dHJhIikKICAgIGluc3RhbGwucGFja2FnZXMoImdyaWRFeHRyYSIpCiAgICBpZihyZXF1aXJlKGdyaWRFeHRyYSkpewogICAgICAgIHByaW50KCJncmlkRXh0cmEgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBncmlkRXh0cmEiKQogICAgfQp9CgojI2ZvciBncmlkLmFycmFuZ2UgZnVuY3Rpb24gdG8gY2hhbmdlIHNpemUgb2YgdGl0bGUKaWYocmVxdWlyZSgiZ3JpZCIpKXsKICAgIHByaW50KCJncmlkIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGdyaWQiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ3JpZCIpCiAgICBpZihyZXF1aXJlKGdyaWQpKXsKICAgICAgICBwcmludCgiZ3JpZCBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdyaWQiKQogICAgfQp9CgojIyBmb3IgZG9pbmcgYnVsayBjb3JyZWxhdGlvbiBjYWxjdWxhdGlvbnMKaWYocmVxdWlyZSgiSG1pc2MiKSl7CiAgICBwcmludCgiSG1pc2MgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgSG1pc2MiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiSG1pc2MiKQogICAgaWYocmVxdWlyZShIbWlzYykpewogICAgICAgIHByaW50KCJIbWlzYyBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIEhtaXNjIikKICAgIH0KfQoKIyMgZHBseXIgaXMgbmVlZGVkIHRvIHdvcmsgd2l0aCBkYXRhIGZyYW1lcwppZihyZXF1aXJlKCJkcGx5ciIpKXsKICAgIHByaW50KCJkcGx5ciBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBkcGx5ciIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpCiAgICBpZihyZXF1aXJlKGRwbHlyKSl7CiAgICAgICAgcHJpbnQoImRwbHlyIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgZHBseXIiKQogICAgfQp9CgojIyBzY2FsZXMgaXMgbmVlZGVkIGZvciBicmVhayBmb3JtYXR0aW5nIGZ1bmN0aW9ucyBpbiB0aGUgYmFyY29kZSBwbG90CmlmKHJlcXVpcmUoInNjYWxlcyIpKXsKICAgIHByaW50KCJzY2FsZXMgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgc2NhbGVzIikKICAgIGluc3RhbGwucGFja2FnZXMoInNjYWxlcyIpCiAgICBpZihyZXF1aXJlKHNjYWxlcykpewogICAgICAgIHByaW50KCJzY2FsZXMgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBzY2FsZXMiKQogICAgfQp9CgojIyBnZ3B1YnIgaXMgbmVlZGVkIGZvciBwbG90dGluZwppZihyZXF1aXJlKCJnZ3B1YnIiLCBxdWlldGx5ID0gVFJVRSkpewogICAgcHJpbnQoImdncHViciBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBnZ3B1YnIiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwdWJyIikKICAgIGlmKHJlcXVpcmUoZ2dwdWJyKSl7CiAgICAgICAgcHJpbnQoImdncHViciBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdncHViciIpCiAgICB9Cn0KCiMjIHBhdGNod29yayBpcyBuZWVkZWQgZm9yIHBsb3R0aW5nCiMjIFdBUk5JTkchIGNvd3Bsb3Qgb3Zlci1yaWRlcyB0aGlzIGJ5IG1hc2tpbmcgaXQgc28gYmUgY2FyZWZ1bC4KaWYocmVxdWlyZSgicGF0Y2h3b3JrIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJwYXRjaHdvcmsgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgcGF0Y2h3b3JrIikKICAgIGluc3RhbGwucGFja2FnZXMoInBhdGNod29yayIpCiAgICBpZihyZXF1aXJlKHBhdGNod29yaykpewogICAgICAgIHByaW50KCJwYXRjaHdvcmsgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBwYXRjaHdvcmsiKQogICAgfQp9CgojIyBzZXQgdGhlIHNlZWQgZm9yIGJvdGggdGhlIG1peHR1cmUgbW9kZWxzIGFuZCBhbHNvIGZvciB0aGUgc2FtcGxlIGZ1bmN0aW9uIGxhdGVyIG9uOgpzZXQuc2VlZCgtOTI0OTcpCmBgYAoKIyMjIEltcG9ydCBHVEYgZmlsZQoKVGhpcyB3aWxsIGJlIGhlbHBmdWwgbGF0ZXIgb24uIFRoaXMgY29udGFpbnMgYW5ub3RhdGlvbnMgZm9yIGVhY2ggZ2VuZToKYGBge3IgaW1wb3J0IGd0Zn0KIyNJbXBvcnQgZ3RmIGZpbGU6Cmd0ZiA8LSByZWFkLnRhYmxlKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YS9SZWZlcmVuY2UvUGJlcmdoZWkuZ3RmIiwgc2VwPSJcdCIsIGhlYWRlciA9IEZBTFNFKQpoZWFkKGd0ZikKYGBgCgojIyMgUmVhZCBpbiB0aGUgRGF0YQoKYGBge3IgaW1wb3J0IGRhdGF9CiMjIHJlYWQgaW4gMTB4IG91dHB1dCAKdGVueDVrX3Jhd19kYXRhIDwtIFJlYWQxMFgoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhLzEwWC90ZW54XzI0Mjg0IikKCiMjIENyZWF0ZSBTZXVyYXQgb2JqZWN0CnRlbng1ayA8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gdGVueDVrX3Jhd19kYXRhLCBtaW4uY2VsbHMgPSAwLCBtaW4uZmVhdHVyZXMgPSAwLCBwcm9qZWN0ID0gIkdDU0tPIikKCiMjIGFkZCBleHBlcmltZW50IHRvIG1ldGEgZGF0YSBmb3IgbWVyZ2luZyBsYXRlcgp0ZW54NWtAbWV0YS5kYXRhJGV4cGVyaW1lbnQgPC0gInRlbng1ayIKCiMjIGluc3BlY3QKdGVueDVrCmBgYAoKIyAzLiBEZWZpbmluZyBDZWxscyB2cy4gQmFja2dyb3VuZCB7LnRhYnNldH0KClBsb3QgYSBrbmVlIHBsb3QgYW5kIHRoZW4gdXNlIGEgbWl4dHVyZSBtb2RlbCB0byBkZWZpbmUgd2hlcmUgdGhlIGNlbGxzIHZzLiBiYWNrZ3JvdW5kIGxpZQpgYGB7ciBtaXhtb2RlbCBzZXR1cH0KIyMgaW50ZXJlc3RpbmcgcmVmZXJlbmNlIG1hdGVyaWFsIGZvciB0aGlzIHNlY3Rpb24gY2FuIGJlIGZvdW5kIGhlcmU6IGh0dHBzOi8vaGVtYmVyZy1sYWIuZ2l0aHViLmlvL3NjUk5BLnNlcS5jb3Vyc2UvcHJvY2Vzc2luZy1yYXctc2NybmEtc2VxLWRhdGEuaHRtbCAKCiMjIGdldCB0aGUgblVNSXMKdW1pX3Blcl9iYXJjb2RlIDwtIGFzLmRhdGEuZnJhbWUodGVueDVrQG1ldGEuZGF0YSRuQ291bnRfUk5BKQoKIyMgcmVtb3ZlIHplcm9zIGFzIHRoZXNlIGhhdmUgaXNzdWVzIHdoZW4geW91IGxvZyB0aGVtIGFuZCBtYWtlIHRoZSBtb2RlbCBsYXRlcjoKdW1pX3Blcl9iYXJjb2RlIDwtIGFzLmRhdGEuZnJhbWUodW1pX3Blcl9iYXJjb2RlWyEodW1pX3Blcl9iYXJjb2RlJGB0ZW54NWtAbWV0YS5kYXRhJG5Db3VudF9STkFgPT0wKSwgXSkKCiMjIGdldCBhIHJhbmsgZm9yIGVhY2ggYmFyY29kZQpiYXJjb2RlX3JhbmsgPC0gcmFuaygtdW1pX3Blcl9iYXJjb2RlWywxXSkKCiMjIHRoZW4gbWFrZSBpbnRvIGEgbGlzdApsaWJfc2l6ZSA8LSAodW1pX3Blcl9iYXJjb2RlWywxXSkKCiMjIHRoZW4gbG9nIHRoaXMKbG9nX2xpYl9zaXplIDwtIGxvZzEwKHVtaV9wZXJfYmFyY29kZVssMV0pCgojI3Bsb3QKI3Bsb3QoYmFyY29kZV9yYW5rLCBsb2dfbGliX3NpemUsIHhsaW09YygxLDEwMDAwMCkpCgojIyBvcmRlciB0aGUgYmFyY29kZSByYW5rcwpvIDwtIG9yZGVyKGJhcmNvZGVfcmFuaykKCiMjIHJlb3JkZXIgdGhlIGxpYnJhcnkgc2l6ZSwgYmFyY29kZSByYW5rIGJ5IHRoZWlyIHJhbmsKbG9nX2xpYl9zaXplIDwtIGxvZ19saWJfc2l6ZVtvXQpiYXJjb2RlX3JhbmsgPC0gYmFyY29kZV9yYW5rW29dCmxpYl9zaXplIDwtIGxpYl9zaXplW29dCmBgYAoKbWFrZSBhIG1peHR1cmUgbW9kZWwgdG8gZGV0ZXJtaW5lIHRoZSBrbmVlIG9mIHRoZSBwbG90CmBgYHtyIG1peG1vZGVsIGNhbGN9CiMjIHNldCBhIHNlZWQgZm9yIHRoZSBtaXh0dXJlIG1vZGVsCnNldC5zZWVkKC05MjQ5NykKCiMjIG1peHR1cmUgbW9kZWwgY2FsY3VsYXRpb24gCnJlcXVpcmUoIm1peHRvb2xzIikKbWl4IDwtIG5vcm1hbG1peEVNKGxvZ19saWJfc2l6ZSkKCiMjIHBsb3QgcmVzdWx0CnBsb3QobWl4LCB3aGljaD0yLCB4bGFiMj0ibG9nKG1vbCBwZXIgY2VsbCkiKQpgYGAKCkZpbmQgd2hlcmUgdGhlIGRpc3RyaWJ1dGlvbnMgaW50ZXJzZWN0IChpLmUuIHdoZXJlIGNlbGxzIHZzLiBiYWNrZ3JvdW5kIGlzKQpgYGB7ciBjYWxjdWxhdGUgc3BsaXR9CiMjIGlkZW50aWZ5IHdoZXJlIHRoZSBzcGxpdCBiZXR3ZWVuIHRoZSBkaXN0cmlidXRpb25zIGlzCnAxIDwtIGRub3JtKGxvZ19saWJfc2l6ZSwgbWVhbj1taXgkbXVbMV0sIHNkPW1peCRzaWdtYVsxXSkKcDIgPC0gZG5vcm0obG9nX2xpYl9zaXplLCBtZWFuPW1peCRtdVsyXSwgc2Q9bWl4JHNpZ21hWzJdKQppZiAobWl4JG11WzFdIDwgbWl4JG11WzJdKSB7CiAgICBzcGxpdCA8LSBtaW4obG9nX2xpYl9zaXplW3AyID4gcDFdKQp9IGVsc2UgewogICAgc3BsaXQgPC0gbWluKGxvZ19saWJfc2l6ZVtwMSA+IHAyXSkKfQoKIyMgcHJpbnQgc3BsaXQKc3BsaXQKYGBgCgpWaWV3IHRoZSBpbml0aWFsIHJlc3VsdApgYGB7cn0KIyMgbG9nIHRoZSBiYXJjb2RlIHJhbmsKbG9nX2JhcmNvZGVfcmFuayA8LSBsb2cxMChiYXJjb2RlX3JhbmspCgojIyBwbG90CnBsb3QobG9nX2JhcmNvZGVfcmFuaywgbG9nX2xpYl9zaXplLCB4bGltPWMoMSw2KSkKIyMgYWRkIHRoZSBzcGxpdCBhcyBhIGxpbmUgb24gdGhlIHBsb3QKYWJsaW5lKGg9c3BsaXQsIGNvbD0icmVkIikKYGBgCgpGaW5hbCBGaWd1cmVzOgpgYGB7ciBiYXJjb2RlIHBsb3R9CiMjIG1ha2UgdGhlIHJlc3VsdHMgb2YgdGhlIGFib3ZlIGZ1bmN0aW9ucyBpbnRvIGEgZGF0YWZyYW1lCmRmX2JhcmNvZGVzIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoYmFyY29kZV9yYW5rLCBsb2dfbGliX3NpemUsIGxpYl9zaXplKSwgcm93Lm5hbWVzID0gTlVMTCkKCiMjIGFkZCBhIGNvbHVtbiBmb3IgaWYgaXQgaXMgYSBjZWxsIG9yIG5vdApkZl9iYXJjb2RlcyRjZWxsID0gcm93bmFtZXMoZGZfYmFyY29kZXMpICVpbiUgd2hpY2goZGZfYmFyY29kZXMkbG9nX2xpYl9zaXplID4gc3BsaXQpCgojIyBjaGFuZ2UgdmFsdWUgdG8gYSBudW1lcmljCmRmX2JhcmNvZGVzJGNlbGwgPC0gYXMubnVtZXJpYyhkZl9iYXJjb2RlcyRjZWxsKQoKIyMgY2hhbmdlIHRoZSAwIHRvIGEgMiBmb3IgZWFzZSBvZiBoYW5kbGluZwpkZl9iYXJjb2RlcyRjZWxsW2RmX2JhcmNvZGVzJGNlbGw8MV0gPC0gMgoKIyMgcmVuYW1lIHRoZSBudW1lcmljcyBpbnRvIGNlbGxzIG9yIGJhY2tncm91bmQKZGZfYmFyY29kZXMkY2VsbFtkZl9iYXJjb2RlcyRjZWxsID09IDFdIDwtICJDZWxscyIKZGZfYmFyY29kZXMkY2VsbFtkZl9iYXJjb2RlcyRjZWxsID09IDJdIDwtICJCYWNrZ3JvdW5kIgoKIyMgZXh0cmFjdCB0aGUgY3V0b2ZmIGZvciBjZWxscyBkbyB5b3UgY2FuIHBsb3QgdGhlIGxpbmVzCmJvdW5kYXJ5IDwtIGFzLm51bWVyaWMoc3VtKGRmX2JhcmNvZGVzJGNlbGwgPT0gIkNlbGxzIikpCnNwbGl0IDwtIDEwXnNwbGl0CgojIyBtYWtlIHRoZSBwbG90CmJhcmNvZGVfcGxvdCA8LSBnZ3Bsb3QoZGZfYmFyY29kZXMsIGFlcyh4PWJhcmNvZGVfcmFuaywgeT1saWJfc2l6ZSwgY29sb3VyID0gY2VsbCwgdGhlbWVfc2l6ZSA9IDQwKSkgKwogICMjIG1ha2UgaW50byBhIGRvdCBwbG90CiAgZ2VvbV9wb2ludChzaXplID0gMSwgc2hhcGUgPSAxNikgKwogICMjIG1ha2UgdGhlIGF4aXMgaW50byBsb2cgYW5kIHNwZWNpZnkgYnJlYWtzCiAgc2NhbGVfeF9sb2cxMChicmVha3MgPSB0cmFuc19icmVha3MoImxvZzEwIiwgZnVuY3Rpb24oeCkgMTBeeCksIGxhYmVscyA9IHRyYW5zX2Zvcm1hdCgibG9nMTAiLCBtYXRoX2Zvcm1hdCgxMF4ueCkpKSArCiAgIyMgbWFrZSB0aGUgYXhpcyBpbnRvIGxvZyBhbmQgc3BlY2lmeSBicmVha3MKICBzY2FsZV95X2xvZzEwKGJyZWFrcyA9IHRyYW5zX2JyZWFrcygibG9nMTAiLCBmdW5jdGlvbih4KSAxMF54KSwgbGFiZWxzID0gdHJhbnNfZm9ybWF0KCJsb2cxMCIsIG1hdGhfZm9ybWF0KDEwXi54KSkpICsKICBhbm5vdGF0aW9uX2xvZ3RpY2tzKCkgKwogICMjIGNoYW5nZSBjb2xvdXJzIG9mIHBsb3QKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiNiZGJkYmQiLCAiIzViYTQzYSIpLCBsYWJlbHMgPSBjKCJCYWNrZ3JvdW5kIiwgIkNlbGxzIikpICsKICAjIyBjaGFuZ2UgYWVzIG9mIGxlZ2VuZAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTI1KSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MjUpLCBheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MjUpKSArCiAgIyMgYWRkIHRoZSBsaW5lcyBvbiB0aGUgcGxvdAogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSBzcGxpdCwgeGVuZCA9IGJvdW5kYXJ5LCB5ZW5kID0gc3BsaXQpLCBjb2xvdXIgPSAiYmxhY2siLCBhbHBoYSA9IDAuMDEpICsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSBib3VuZGFyeSwgeSA9IDAsIHhlbmQgPSBib3VuZGFyeSwgeWVuZCA9IHNwbGl0KSwgY29sb3VyID0gImJsYWNrIiwgYWxwaGEgPSAwLjAxKSArCiAgIyMgY2hhbmdlIHRoZSBheGlzIGxhYmVscwogIGxhYnMoeCA9ICJCYXJjb2RlcyIsIHkgPSAiVU1JIENvdW50cyIsIGNvbG91cj0iQ2VsbCBEZXNpZ25hdGlvbiIpICsKICAjIyBjaGFuZ2UgdGhlIHNpemUgb2YgdGhlIGxlZ2VuZAogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTEwKSkpICsKICAjIyBmaXggYXhpcwogIGNvb3JkX2ZpeGVkKCkgKwogICMjIG1ha2UgaXQgbG9vayBwcmV0dHkKICB0aGVtZV9saWdodCgpCgojIyBwcmludCB0aGUgcGxvdApiYXJjb2RlX3Bsb3QKCiMjIHNhdmUgdGhlIHBsb3QKZ2dzYXZlKCJRQ18xMFhfYmFyY29kZV9wbG90XzVrLnBuZyIsIHBsb3QgPSBiYXJjb2RlX3Bsb3QsIGRldmljZSA9ICJwbmciLCBoZWlnaHQgPSAxNSwgd2lkdGggPSAxNSwgdW5pdHMgPSAiY20iLCBwYXRoID0gIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9pbWFnZXNfdG9fZXhwb3J0LyIpCmBgYAoKc28gdGhlIG51bWJlciBvZiBjZWxscyB0aGF0IGlzIHJldGFpbmVkIGlzOgpgYGB7ciwgZWNobyA9IEZBTFNFfQp0YWJsZShkZl9iYXJjb2RlcyRjZWxsKQpgYGAKCiMjIyBGaWx0ZXIgdGhlIG9iamVjdAoKYGBge3IgZmlsdGVyIGNlbGxzIHZzIGJhY2tncm91bmR9CiMjIGV4dHJhY3QgdGhlIG5Db3VudCBhbmQgcm93IG5hbWVzIGZyb20gdGhlIFNldXJhdCBvYmplY3QKdXBiIDwtIGRhdGEuZnJhbWUobkNvdW50X1JOQSA9IHRlbng1a0BtZXRhLmRhdGEkbkNvdW50X1JOQSwgcm93Lm5hbWVzID0gcm93bmFtZXModGVueDVrQG1ldGEuZGF0YSkpCgojIyBtYWtlIGJsYW5rIGNvbHVtbiBmb3IgcmFuawp1cGIkcmFuayA8LSBOQQoKIyMgb3JkZXIgYnkgbkNvdW50cwpvcmRlci5zY29yZXMgPC0gb3JkZXIodXBiJG5Db3VudF9STkEsIGRlY3JlYXNpbmcgPSBUUlVFKQoKIyMgYWRkIGEgcmFuayB0byB0aGlzIGNvbHVtbiBiYXNlZCBvbiB0aGUgb3JkZXJlZCBuQ291bnQKdXBiJHJhbmtbb3JkZXIuc2NvcmVzXSA8LSAxOm5yb3codXBiKQoKIyMgaW5zcGVjdAojaGVhZCh1cGIpCgojIyBtYWtlIGEgbGlzdCBvZiBjZWxscyB0byByZXRhaW4gaW4gdGhlIFNldXJhdCBvYmplY3QKa2VlcF9jZWxscyA8LSByb3duYW1lcyh1cGJbd2hpY2godXBiJHJhbmsgPCA3NzYzKSxdKQoKIyMgc3Vic2V0IFNldXJhdCBvYmplY3QgdG8gaW5jbHVkZSBjZWxscyBhbmQgZGlzY2FyZCBiYWNrZ3JvdW5kCnBiX3NleCA8LSBzdWJzZXQodGVueDVrLCBjZWxscyA9IGtlZXBfY2VsbHMpCmBgYAoKIyA0LiBGaWx0ZXIgT3V0IFBvb3ItUXVhbGl0eSBDZWxscyB7LnRhYnNldH0KCiMjIyBGaWx0ZXIgTWl0b2Nob25kcmlhbCAlCgpNaXRvY2hvbmRyaWFsIGNlbGwgY291bnRzCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTUsIGZpZy53aWR0aCA9IDd9CiMjIGV4dHJhY3QgbWl0b2Nob25kcmlhbCBnZW5lcyAKI21pdG9fZ2VuZXMgPC0gZ3RmW3doaWNoKGd0ZiRWMyA9PSAiclJOQSIpLF0kVjkKI21pdG9fZ2VuZXMgPC0gZ3N1YigiOy4qIiwiIiwgZ3N1YigiZ2VuZV9pZCAiLCAiIiwgbWl0b19nZW5lcykpCiNwYXN0ZSgiVGhlc2UgYXJlIHRoZSBtaXRvY2hvbmRyaWFsIGdlbmVzIikKI2hlYWQobWl0b19nZW5lcykKCiMjIGV4dHJhY3QgbWl0byBnZW5lcwptaXRvX2dlbmVzIDwtIHBiX3NleEBhc3NheXMkUk5BQGNvdW50c0BEaW1uYW1lc1tbMV1dW2dyZXAoIl5QQkFOS0EtTUlUIixwYl9zZXhAYXNzYXlzJFJOQUBjb3VudHNARGltbmFtZXNbWzFdXSldCgojIyBwbG90IHRoZSBnZW5lcyBpbmRpdmlkdWFsbHkKVmxuUGxvdChvYmplY3QgPSBwYl9zZXgsIGZlYXR1cmVzID0gbWl0b19nZW5lcywgcHQuc2l6ZSA9IDAuMDEpCgojIyBtYWtlIGEgcGVyY2VudGFnZSBtaXRvY29uZHJpYWwgZm9yIGVhY2ggY2VsbCAodGhpcyB3aWxsIHdvcmsgYXMgbG9uZyBhcyB5b3UgZmlsdGVyIGNlbGxzIG91dCB3aXRoIHplcm8gY291bnRzKQpwYl9zZXggPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQocGJfc2V4LCBwYXR0ZXJuID0gIl5QQkFOS0EtTUlUIiwgY29sLm5hbWUgPSAicGVyY2VudC5tdCIpCmBgYAoKcGxvdCBwZXJjZW50YWdlIG1pdG9jaG9uZHJpYWwKYGBge3J9CiMjIHBsb3QgZm9yIHBlcmNlbnRhZ2Ugb2YgbWl0b2Nob25kcmlhbCByZWFkcwp2MSA8LSBWbG5QbG90KG9iamVjdCA9IHBiX3NleCwgZmVhdHVyZXMgPSAicGVyY2VudC5tdCIsIHB0LnNpemUgPSAwLjAxKSArCiAgIyMgYWRkIGEgbGluZSB3aGVyZSB3ZSB3aWxsIGZpbHRlcgogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDIwLCBjb2w9ImJsdWUiKSArCiAgIyMgY2hhbmdlIGxhYmVscwogIGxhYnMoeCA9ICIiLHkgPSAiJSBNaXRvY2hvbmRyaWFsIFJlYWRzIiwgdGl0bGUgPSAiTWl0b2Nob25kcmlhbCBwZXIgY2VsbCIpICsKICAjIyByZW1vdmUgbGVnZW5kCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgIyMgY2hhbmdlIGFwcGVhcmFuY2UKICB0aGVtZV9jbGFzc2ljKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0iZ3JleSIpICsKICAjc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMTAwKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLCB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChjb2xvdXI9ImJsYWNrIikpCgojIyBwcmludAp2MQoKIyMgc2F2ZQojZ2dzYXZlKCJ+L2ltYWdlc190b19leHBvcnQvUUNfMTBYX21pdG9fdmlvbGluLnBuZyIsIHBsb3QgPSBRQ19taXRvX3Zpb2xpbiwgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLCBzY2FsZSA9IDEsIHdpZHRoID0gMTUsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCwgbGltaXRzaXplID0gVFJVRSkKYGBgCgpJbiB0aGUgU21hcnQtc2VxMiBkYXRhLCB3ZSB1c2UgYSB0aHJlc2hvbGQgb2YgMjAlLiBObyBjZWxsIGluIG91ciAxMFggZGF0YSBpcyBoaWdoZXIgdGhhbiAxMyUgYW5kIG9ubHkKYGBge3IsIGVjaG8gPSBGQUxTRX0Kc3VtKHBiX3NleEBtZXRhLmRhdGEkcGVyY2VudC5tdCA+IDUpCmBgYApjZWxscyBoYXZlIGEgJSBtaXRvY2hvbmRyaWFsIHJlYWRzIGFib3ZlIDUlLiAKCiMjIyBuR2VuZXMgZmlsdGVyCgpwbG90IGluZGl2aWR1YWwgdmlvbGluIHBsb3RzCmBgYHtyfQojIyBuR2VuZXMgcGxvdApnZW5lX3Bsb3RfNWsgPC0gVmxuUGxvdChvYmplY3QgPSBwYl9zZXgsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIHB0LnNpemUgPSAwLjAxKQoKIyMgaW1wcm92ZSB0aGUgYWVzdGhldGljcwpnZW5lX3Bsb3RfNWsgPC0gZ2VuZV9wbG90XzVrICsgCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMjAwLCBjb2w9ImJsdWUiKSArCiAgbGFicyh4ID0gIiIseSA9ICJuR2VuZSIsIHRpdGxlID0gIkdlbmVzIHBlciBjZWxsIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSJncmV5IikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDMwMDApKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTIwKSwgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTIwKSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KGNvbG91cj0iYmxhY2siKSkKCiMjIG5VTUkgcGxvdApudW1pX3Bsb3RfNWsgPC0gVmxuUGxvdChvYmplY3QgPSBwYl9zZXgsIGZlYXR1cmVzID0gIm5Db3VudF9STkEiLCBwdC5zaXplID0gMC4wMSkKCiMjIGltcHJvdmUgYWVzdGhldGljcwpudW1pX3Bsb3RfNWsgPC0gbnVtaV9wbG90XzVrICsKICBsYWJzKHggPSAiIix5ID0gIm5VTUkiLCB0aXRsZSA9ICJVTUlzIHBlciBjZWxsIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSJncmV5IikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDMwMDApKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTIwKSwgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTIwKSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KGNvbG91cj0iYmxhY2siKSkKCiMjIHBsb3QgdG9nZXRoZXIKZ3JpZC5hcnJhbmdlKGdlbmVfcGxvdF81aywgbnVtaV9wbG90XzVrLCBuY29sID0gMiwgdG9wPXRleHRHcm9iKCI1SyBjZWxscyAxMFgiLCBncD1ncGFyKGZvbnRzaXplPTE1LGZvbnQ9OCkpKQoKIyMgc2F2ZSBuR2VuZSBwbG90IG9uIGl0cyBvd24KI2dnc2F2ZSgiUUNfbmdlbmVfcGxvdC5wZGYiLCBwbG90ID0gZ2VuZTEsIGRldmljZSA9ICJwZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDUsIHVuaXRzID0gImluIiwgcGF0aCA9ICIvVXNlcnMvYXIxOS9EZXNrdG9wL1BoRC9HQ1NLT19BbmFseXNpcyIpCmBgYAoKcGxvdCB0d28gbWV0cmljcyB0b2dldGhlcgpgYGB7ciwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDh9CiMjIG1ha2UgYSBkYXRhZnJhbWUgZm9yIGltcG9ydGFudCBmaWx0ZXJpbmcgbWV0cmljcwpkZiA8LSBkYXRhLmZyYW1lKG5Db3VudCA9IGxvZzEwKHBiX3NleEBtZXRhLmRhdGEkbkNvdW50X1JOQSksIG5HZW5lcyA9IHBiX3NleEBtZXRhLmRhdGEkbkZlYXR1cmVfUk5BLCBwZXJjZW50X210ID0gcGJfc2V4QG1ldGEuZGF0YSRwZXJjZW50Lm10LCBleHBlcmltZW50ID0gcGJfc2V4QG1ldGEuZGF0YSRleHBlcmltZW50KQoKIyMgcGxvdCBtYWluIGRvdHBsb3QKcGxvdDEgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IG5Db3VudCwgeSA9IG5HZW5lcykpICsKICAjZ2VvbV9wb2ludChhZXMoKSwgc2l6ZSA9IDAuMSkgKwogIGdlb21faGV4KGJpbnMgPSAyMDApICsKICAjZ2VvbV9ydWcoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIk51bWJlciBvZiBEZXRlY3RlZCBHZW5lcyIpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAibG9nMTAoTnVtYmVyIG9mIFRvdGFsIFVNSSkiKSArIAogIHRoZW1lX3B1YnIoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MjAwKQoKIyMgcGxvdCBkZW5zaXR5IHBsb3QgeApkZW5zIDwtIGRlbnNpdHkoZGYkbkNvdW50KQpkdCA8LSBkYXRhLmZyYW1lKHg9ZGVucyR4LCB5PWRlbnMkeSkKcHJvYnMgPC0gYygwLCAwLjI1LCAwLjUsIDAuNzUsIDEpCnF1YW50aWxlcyA8LSBxdWFudGlsZShkZiRuQ291bnQsIHByb2I9cHJvYnMpCmR0JHF1YW50IDwtIGZhY3RvcihmaW5kSW50ZXJ2YWwoZHQkeCxxdWFudGlsZXMpKQpkZW5zMSA8LSBnZ3Bsb3QoZHQsIGFlcyh4LHkpKSArIGdlb21fbGluZSgpICsgZ2VvbV9yaWJib24oYWVzKHltaW49MCwgeW1heD15LCBmaWxsPXF1YW50KSkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXF1YW50aWxlcykgKyBzY2FsZV9maWxsX2JyZXdlcihndWlkZT0ibm9uZSIpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQojIyBwbG90IGRlbnNpdHkgcGxvdCB5CiMjIG9sZCBtZXRob2QKIyBkZW5zMiA8LSBnZ3Bsb3QoZGYsIGFlcyh4ID0gbkdlbmVzLCB5ID0gZXhwZXJpbWVudCkpICsKIyAgIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuMikgKwojICAgdGhlbWVfdm9pZCgpICsKIyAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwojICAgY29vcmRfZmxpcCgpCiMjIG5ldyBtZXRob2QKZGVucyA8LSBkZW5zaXR5KGRmJG5HZW5lcykKZHQgPC0gZGF0YS5mcmFtZSh4PWRlbnMkeCwgeT1kZW5zJHkpCnByb2JzIDwtIGMoMCwgMC4yNSwgMC41LCAwLjc1LCAxKQpxdWFudGlsZXMgPC0gcXVhbnRpbGUoZGYkbkdlbmVzLCBwcm9iPXByb2JzKQpkdCRxdWFudCA8LSBmYWN0b3IoZmluZEludGVydmFsKGR0JHgscXVhbnRpbGVzKSkKZGVuczIgPC0gZ2dwbG90KGR0LCBhZXMoeCx5KSkgKyBnZW9tX2xpbmUoKSArIGdlb21fcmliYm9uKGFlcyh5bWluPTAsIHltYXg9eSwgZmlsbD1xdWFudCkpICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1xdWFudGlsZXMpICsgc2NhbGVfZmlsbF9icmV3ZXIoZ3VpZGU9Im5vbmUiKSArIHRoZW1lX3ZvaWQoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGNvb3JkX2ZsaXAoKQoKIyMgcGxvdCB0b2dldGhlcgpRQ19jb21wb3NpdGVfcGxvdCA8LSBkZW5zMSArIHBsb3Rfc3BhY2VyKCkgKyBwbG90MSArIGRlbnMyICsgcGxvdF9sYXlvdXQobmNvbCA9IDIsIG5yb3cgPSAyLCB3aWR0aHMgPSBjKDQsIDEpLCBoZWlnaHRzID0gYygxLCA0KSkKCiMjIHByaW50ClFDX2NvbXBvc2l0ZV9wbG90CgojIyBzYXZlCmdnc2F2ZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2ltYWdlc190b19leHBvcnQvUUNfMTBYX2NvbXBvc2l0ZV9wbG90LnBuZyIsIHBsb3QgPSBRQ19jb21wb3NpdGVfcGxvdCwgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLCBzY2FsZSA9IDEsIHdpZHRoID0gMTUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCwgbGltaXRzaXplID0gVFJVRSkKYGBgCgojIyMgRmlsdGVyaW5nCgpUaGUgdGhyZXNob2xkIHVzZWQgaW4gdGhlIG1hbGFyaWEgY2VsbCBhdGxhcyB3YXMgMjMwIGZvciBQYiBidXQgdGhpcyBpcyBkZXBlbmRlbnQgb24gc2VxdWVuY2luZyBkZXB0aCBldGMuCldlIGNhbiBwbG90IHRoZSBudW1iZXIgb2YgY2VsbHMgcmVjb3ZlcmVkIGZvciBhIHJhbmdlIG9mIHRocmVzaG9sZHM6CmBgYHtyfQpwYXN0ZSgib3JpZ2luYWwgbnVtYmVyIG9mIGNlbGxzID0iLCBucm93KHBiX3NleEBtZXRhLmRhdGEpKQpwYXN0ZSgid2l0aCA+MTUwIGZpbHRlciA9IiwgbnJvdyhwYl9zZXhAbWV0YS5kYXRhW3BiX3NleEBtZXRhLmRhdGEkbkZlYXR1cmVfUk5BID4gMTUwLCBdKSkKcGFzdGUoIndpdGggPjIwMCBmaWx0ZXIgPSIsIG5yb3cocGJfc2V4QG1ldGEuZGF0YVtwYl9zZXhAbWV0YS5kYXRhJG5GZWF0dXJlX1JOQSA+IDIwMCwgXSkpCnBhc3RlKCJ3aXRoID4yMzAgZmlsdGVyID0iLCBucm93KHBiX3NleEBtZXRhLmRhdGFbcGJfc2V4QG1ldGEuZGF0YSRuRmVhdHVyZV9STkEgPiAyMzAsIF0pKQpgYGAKClNpbmNlIHdlIGhhdmUgYWxyZWFkeSBmaWx0ZXJlZCBvbiBuVU1JLCB3ZSB3aWxsIGZpbHRlciB3aXRoIDIwMC4KCmBgYHtyfQojIyBudW1iZXIgb2YgY2VsbHMgYmVmb3JlIGZpbHRlcmluZwpwYl9zZXhfcHJlX2ZpbHRlcl9uQ2VsbHMgPC0gbnJvdyhwYl9zZXhAbWV0YS5kYXRhKQojIyBmaWx0ZXIgb2JqZWN0CnBiX3NleCA8LSBzdWJzZXQocGJfc2V4LCBzdWJzZXQgPSBuRmVhdHVyZV9STkEgPiAyMDApCiMjIG51bWJlciBvZiBjZWxscyBhZnRlciBmaWx0ZXJpbmcKcGJfc2V4X3Bvc3RfZmlsdGVyX25DZWxscyA8LSBucm93KHBiX3NleEBtZXRhLmRhdGEpCiMjIHByaW50IHJlc3VsdHMgb2YgZmlsdGVyaW5nCnBhc3RlKCJudW1iZXIgb2YgY2VsbHMgcHJlLWZpbHRlciIsIHBiX3NleF9wcmVfZmlsdGVyX25DZWxscykKcGFzdGUoIm51bWJlciBvZiBjZWxscyBwb3N0LWZpbHRlciIsIHBiX3NleF9wb3N0X2ZpbHRlcl9uQ2VsbHMpCnBhc3RlKChwYl9zZXhfcHJlX2ZpbHRlcl9uQ2VsbHMgLSBwYl9zZXhfcG9zdF9maWx0ZXJfbkNlbGxzKSwgImNlbGxzIHdlcmUgcmVtb3ZlZCBieSBmaWx0ZXJpbmcgb24gbnVtYmVyIG9mIGdlbmVzLiIpCmBgYAoKIyA1LiBEaW1lbnNpb25hbGl0eSBSZWR1Y3Rpb24gYW5kIENsdXN0ZXJpbmcgey50YWJzZXR9CgojIyMgUHJlcGFyZSBkYXRhCmBgYHtyfQojIyBub3JtYWxpc2Ugb2JqZWN0CnBiX3NleCA8LSBOb3JtYWxpemVEYXRhKHBiX3NleCwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiTG9nTm9ybWFsaXplIiwgc2NhbGUuZmFjdG9yID0gMTAwMDApCgojIyBmaW5kIHZhcmlhYmxlIGdlbmVzCnBiX3NleCA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhwYl9zZXgsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKCiMjIHNjYWxlIHRoZSBkYXRhCmFsbC5nZW5lcyA8LSByb3duYW1lcyhwYl9zZXgpCnBiX3NleCA8LSBTY2FsZURhdGEocGJfc2V4LCBmZWF0dXJlcyA9IGFsbC5nZW5lcykKYGBgCgojIyMgUENBCmBgYHtyfQojIyBydW4gUENBCnBiX3NleCA8LSBSdW5QQ0EocGJfc2V4LCBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMob2JqZWN0ID0gcGJfc2V4KSkKCiMjIHBsb3QgCkRpbVBsb3QocGJfc2V4LCByZWR1Y3Rpb24gPSAicGNhIikKCiMjIGVsYm93IHBsb3QKRWxib3dQbG90KHBiX3NleCwgbmRpbXMgPSAzMCwgcmVkdWN0aW9uID0gInBjYSIpCmBgYAoKIyMjIFVNQVAKYGBge3J9CiMjIHJ1biBVTUFQCnBiX3NleCA8LSBSdW5VTUFQKHBiX3NleCwgZGltcyA9IDE6MTAsIHNlZWQudXNlID0gMTIzNCwgbi5uZWlnaGJvcnMgPSAxNTApCgojIyBwbG90CkRpbVBsb3QocGJfc2V4LCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gImlkZW50IiwgbGFiZWwgPSBUUlVFKQoKIyMgVGhlc2UgYXJlIHRoZSBwYXJhbWV0ZXJzIHVzZWQgaW4gdGhlIG1lcmdlIFVNQVAKI3BiX3NleCA8LSBSdW5VTUFQKHBiX3NleCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjEwLCBuLm5laWdoYm9ycyA9IDE1MCwgc2VlZC51c2UgPSAxMjM0LCBtaW4uZGlzdCA9IDAuNCwgcmVwdWxzaW9uLnN0cmVuZ3RoID0gMC4wMywgbG9jYWwuY29ubmVjdGl2aXR5ID0gMTUwKQojRGltUGxvdChwYl9zZXgsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiaWRlbnQiLCBsYWJlbCA9IFRSVUUpCmBgYAoKY29sb3VyIHdpdGggYSBmZXcgbWFya2VyIGdlbmVzOgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDh9CiMgUEJBTktBLTA1MTUwMDAgLSBwMjUgLSBmZW1hbGUKIyBQQkFOS0EtMTIxMjYwMCAtIEhBUDIgLSBtYWxlCiMgUEJBTktBLTA2MDA2MDAgLSBORUszIC0gbWFsZQojIFBCQU5LQS0wODMxMDAwIC0gTVNQMSAtIGxhdGUgYXNleHVhbAojIFBCQU5LQS0xMzE1NzAwIC0gUk9OMiAtIChhc2V4dWFscyBhbmQgc29tZSBtYWxlPykKIyBQQkFOS0EtMDQxNjEwMCAtIGR5bmVuaW4gaGVhdnkgY2hhaW4gLSBtYWxlIC0gdXNlZCBpbiA4MjAgbGluZQojIFBCQU5LQS0xMzE5NTAwIC0gQ0NQMiAtIGZlbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUgCiMgUEJBTktBLTE0Mzc1MDAgLSBBUDItRyAtIHNldXhhbCBjb21taXRtZW50IGdlbmUKIyBQQkFOS0EtMTEwMjIwMCAtIE1TUDggLSBlYXJseSBhc2V4dWFsIChmcm9tIEJvemRlY2ggcGFwZXIpCgpGZWF0dXJlUGxvdChwYl9zZXgsIGZlYXR1cmVzID0gYygiUEJBTktBLTA1MTUwMDAiLCAiUEJBTktBLTEyMTI2MDAiLCJQQkFOS0EtMDYwMDYwMCIsICJQQkFOS0EtMDgzMTAwMCIsICJQQkFOS0EtMTMxNTcwMCIsICJQQkFOS0EtMDQxNjEwMCIsICJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMTQzNzUwMCIsICJQQkFOS0EtMTEwMjIwMCIpKQpgYGAKCiMjIyBDbHVzdGVyaW5nCmBgYHtyfQpwYl9zZXggPC0gRmluZE5laWdoYm9ycyhwYl9zZXgsIGRpbXMgPSAxOjIxKQpwYl9zZXggPC0gRmluZENsdXN0ZXJzKHBiX3NleCwgcmVzb2x1dGlvbiA9IDEpCmBgYAoKIyA2LiBSZW1vdmUgRG91YmxldHMgey50YWJzZXR9CgojIyMgRG91YmxldEZpbmRlcgoKRG91YmxldEZpbmRlciBmdW5jdGlvbgpgYGB7cn0KIyMgRG91YmxldEZpbmRlciBzaG91bGQgYmUgYWJsZSB0byBiZSBpbnN0YWxsZWQgYW5kIHJ1biBhcyBzbzoKI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1YignY2hyaXMtbWNnaW5uaXMtdWNzZi9Eb3VibGV0RmluZGVyJykKI2xpYnJhcnkoZG91YmxldEZpbmRlcikgI2FsbG93cyByZW1vdmFsIG9mIGRvdWJsZXRzCiMjIGJ1dCB0aGVyZSBzZWVtcyB0byBiZSBzb21lIHByb2JsZW1zIHdpdGggdGhpcyBzbyB3ZSB3aWxsIHJ1biBpdCBmcm9tIHRoZSBnaXRodWIgY29kZQoKIyMgdGhlIGRvdWJsZXQgZmluZGVyIGZ1bmN0aW9uCmRvdWJsZXRGaW5kZXJfdjMgPC0gZnVuY3Rpb24oc2V1LCBQQ3MsIHBOID0gMC4yNSwgcEssIG5FeHAsIHJldXNlLnBBTk4gPSBGQUxTRSwgc2N0ID0gRkFMU0UpIHsKICByZXF1aXJlKFNldXJhdCk7IHJlcXVpcmUoZmllbGRzKTsgcmVxdWlyZShLZXJuU21vb3RoKQoKICAjIyBHZW5lcmF0ZSBuZXcgbGlzdCBvZiBkb3VibGV0IGNsYXNzaWZpY2F0b25zIGZyb20gZXhpc3RpbmcgcEFOTiB2ZWN0b3IgdG8gc2F2ZSB0aW1lCiAgaWYgKHJldXNlLnBBTk4gIT0gRkFMU0UgKSB7CiAgICBwQU5OLm9sZCA8LSBzZXVAbWV0YS5kYXRhWyAsIHJldXNlLnBBTk5dCiAgICBjbGFzc2lmaWNhdGlvbnMgPC0gcmVwKCJTaW5nbGV0IiwgbGVuZ3RoKHBBTk4ub2xkKSkKICAgIGNsYXNzaWZpY2F0aW9uc1tvcmRlcihwQU5OLm9sZCwgZGVjcmVhc2luZz1UUlVFKVsxOm5FeHBdXSA8LSAiRG91YmxldCIKICAgIHNldUBtZXRhLmRhdGFbLCBwYXN0ZSgiREYuY2xhc3NpZmljYXRpb25zIixwTixwSyxuRXhwLHNlcD0iXyIpXSA8LSBjbGFzc2lmaWNhdGlvbnMKICAgIHJldHVybihzZXUpCiAgfQoKICBpZiAocmV1c2UucEFOTiA9PSBGQUxTRSkgewogICAgIyMgTWFrZSBtZXJnZWQgcmVhbC1hcnRpZmljYWwgZGF0YQogICAgcmVhbC5jZWxscyA8LSByb3duYW1lcyhzZXVAbWV0YS5kYXRhKQogICAgZGF0YSA8LSBzZXVAYXNzYXlzJFJOQUBjb3VudHNbLCByZWFsLmNlbGxzXQogICAgbl9yZWFsLmNlbGxzIDwtIGxlbmd0aChyZWFsLmNlbGxzKQogICAgbl9kb3VibGV0cyA8LSByb3VuZChuX3JlYWwuY2VsbHMvKDEgLSBwTikgLSBuX3JlYWwuY2VsbHMpCiAgICBwcmludChwYXN0ZSgiQ3JlYXRpbmciLG5fZG91YmxldHMsImFydGlmaWNpYWwgZG91YmxldHMuLi4iLHNlcD0iICIpKQogICAgcmVhbC5jZWxsczEgPC0gc2FtcGxlKHJlYWwuY2VsbHMsIG5fZG91YmxldHMsIHJlcGxhY2UgPSBUUlVFKQogICAgcmVhbC5jZWxsczIgPC0gc2FtcGxlKHJlYWwuY2VsbHMsIG5fZG91YmxldHMsIHJlcGxhY2UgPSBUUlVFKQogICAgZG91YmxldHMgPC0gKGRhdGFbLCByZWFsLmNlbGxzMV0gKyBkYXRhWywgcmVhbC5jZWxsczJdKS8yCiAgICBjb2xuYW1lcyhkb3VibGV0cykgPC0gcGFzdGUoIlgiLCAxOm5fZG91YmxldHMsIHNlcCA9ICIiKQogICAgZGF0YV93ZG91YmxldHMgPC0gY2JpbmQoZGF0YSwgZG91YmxldHMpCgogICAgIyMgU3RvcmUgaW1wb3J0YW50IHByZS1wcm9jZXNzaW5nIGluZm9ybWF0aW9uCiAgICBvcmlnLmNvbW1hbmRzIDwtIHNldUBjb21tYW5kcwoKICAgICMjIFByZS1wcm9jZXNzIFNldXJhdCBvYmplY3QKICAgIGlmIChzY3QgPT0gRkFMU0UpIHsKICAgICAgcHJpbnQoIkNyZWF0aW5nIFNldXJhdCBvYmplY3QuLi4iKQogICAgICBzZXVfd2RvdWJsZXRzIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBkYXRhX3dkb3VibGV0cykKCiAgICAgIHByaW50KCJOb3JtYWxpemluZyBTZXVyYXQgb2JqZWN0Li4uIikKICAgICAgc2V1X3dkb3VibGV0cyA8LSBOb3JtYWxpemVEYXRhKHNldV93ZG91YmxldHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemF0aW9uLm1ldGhvZCA9IG9yaWcuY29tbWFuZHMkTm9ybWFsaXplRGF0YS5STkFAcGFyYW1zJG5vcm1hbGl6YXRpb24ubWV0aG9kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUuZmFjdG9yID0gb3JpZy5jb21tYW5kcyROb3JtYWxpemVEYXRhLlJOQUBwYXJhbXMkc2NhbGUuZmFjdG9yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFyZ2luID0gb3JpZy5jb21tYW5kcyROb3JtYWxpemVEYXRhLlJOQUBwYXJhbXMkbWFyZ2luKQoKICAgICAgcHJpbnQoIkZpbmRpbmcgdmFyaWFibGUgZ2VuZXMuLi4iKQogICAgICBzZXVfd2RvdWJsZXRzIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNldV93ZG91YmxldHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0aW9uLm1ldGhvZCA9IG9yaWcuY29tbWFuZHMkRmluZFZhcmlhYmxlRmVhdHVyZXMuUk5BJHNlbGVjdGlvbi5tZXRob2QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9lc3Muc3BhbiA9IG9yaWcuY29tbWFuZHMkRmluZFZhcmlhYmxlRmVhdHVyZXMuUk5BJGxvZXNzLnNwYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpcC5tYXggPSBvcmlnLmNvbW1hbmRzJEZpbmRWYXJpYWJsZUZlYXR1cmVzLlJOQSRjbGlwLm1heCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuLmZ1bmN0aW9uID0gb3JpZy5jb21tYW5kcyRGaW5kVmFyaWFibGVGZWF0dXJlcy5STkEkbWVhbi5mdW5jdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwZXJzaW9uLmZ1bmN0aW9uID0gb3JpZy5jb21tYW5kcyRGaW5kVmFyaWFibGVGZWF0dXJlcy5STkEkZGlzcGVyc2lvbi5mdW5jdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW0uYmluID0gb3JpZy5jb21tYW5kcyRGaW5kVmFyaWFibGVGZWF0dXJlcy5STkEkbnVtLmJpbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5uaW5nLm1ldGhvZCA9IG9yaWcuY29tbWFuZHMkRmluZFZhcmlhYmxlRmVhdHVyZXMuUk5BJGJpbm5pbmcubWV0aG9kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5mZWF0dXJlcyA9IG9yaWcuY29tbWFuZHMkRmluZFZhcmlhYmxlRmVhdHVyZXMuUk5BJG5mZWF0dXJlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuLmN1dG9mZiA9IG9yaWcuY29tbWFuZHMkRmluZFZhcmlhYmxlRmVhdHVyZXMuUk5BJG1lYW4uY3V0b2ZmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BlcnNpb24uY3V0b2ZmID0gb3JpZy5jb21tYW5kcyRGaW5kVmFyaWFibGVGZWF0dXJlcy5STkEkZGlzcGVyc2lvbi5jdXRvZmYpCgogICAgICBwcmludCgiU2NhbGluZyBkYXRhLi4uIikKICAgICAgc2V1X3dkb3VibGV0cyA8LSBTY2FsZURhdGEoc2V1X3dkb3VibGV0cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBvcmlnLmNvbW1hbmRzJFNjYWxlRGF0YS5STkEkZmVhdHVyZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLnVzZSA9IG9yaWcuY29tbWFuZHMkU2NhbGVEYXRhLlJOQSRtb2RlbC51c2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvLnNjYWxlID0gb3JpZy5jb21tYW5kcyRTY2FsZURhdGEuUk5BJGRvLnNjYWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkby5jZW50ZXIgPSBvcmlnLmNvbW1hbmRzJFNjYWxlRGF0YS5STkEkZG8uY2VudGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZS5tYXggPSBvcmlnLmNvbW1hbmRzJFNjYWxlRGF0YS5STkEkc2NhbGUubWF4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBibG9jay5zaXplID0gb3JpZy5jb21tYW5kcyRTY2FsZURhdGEuUk5BJGJsb2NrLnNpemUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5jZWxscy50by5ibG9jayA9IG9yaWcuY29tbWFuZHMkU2NhbGVEYXRhLlJOQSRtaW4uY2VsbHMudG8uYmxvY2spCgogICAgICBwcmludCgiUnVubmluZyBQQ0EuLi4iKQogICAgICBzZXVfd2RvdWJsZXRzIDwtIFJ1blBDQShzZXVfd2RvdWJsZXRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IG9yaWcuY29tbWFuZHMkU2NhbGVEYXRhLlJOQSRmZWF0dXJlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnBjcyA9IGxlbmd0aChQQ3MpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXYucGNhID0gIG9yaWcuY29tbWFuZHMkUnVuUENBLlJOQSRyZXYucGNhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQuYnkudmFyID0gb3JpZy5jb21tYW5kcyRSdW5QQ0EuUk5BJHdlaWdodC5ieS52YXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9RkFMU0UpCiAgICAgIHBjYS5jb29yZCA8LSBzZXVfd2RvdWJsZXRzQHJlZHVjdGlvbnMkcGNhQGNlbGwuZW1iZWRkaW5nc1sgLCBQQ3NdCiAgICAgIGNlbGwubmFtZXMgPC0gcm93bmFtZXMoc2V1X3dkb3VibGV0c0BtZXRhLmRhdGEpCiAgICAgIG5DZWxscyA8LSBsZW5ndGgoY2VsbC5uYW1lcykKICAgICAgcm0oc2V1X3dkb3VibGV0cyk7IGdjKCkgIyBGcmVlIHVwIG1lbW9yeQogICAgfQoKICAgIGlmIChzY3QgPT0gVFJVRSkgewogICAgICByZXF1aXJlKHNjdHJhbnNmb3JtKQogICAgICBwcmludCgiQ3JlYXRpbmcgU2V1cmF0IG9iamVjdC4uLiIpCiAgICAgIHNldV93ZG91YmxldHMgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IGRhdGFfd2RvdWJsZXRzKQoKICAgICAgcHJpbnQoIlJ1bm5pbmcgU0NUcmFuc2Zvcm0uLi4iKQogICAgICBzZXVfd2RvdWJsZXRzIDwtIFNDVHJhbnNmb3JtKHNldV93ZG91YmxldHMpCgogICAgICBwcmludCgiUnVubmluZyBQQ0EuLi4iKQogICAgICBzZXVfd2RvdWJsZXRzIDwtIFJ1blBDQShzZXVfd2RvdWJsZXRzLCBucGNzID0gbGVuZ3RoKFBDcykpCiAgICAgIHBjYS5jb29yZCA8LSBzZXVfd2RvdWJsZXRzQHJlZHVjdGlvbnMkcGNhQGNlbGwuZW1iZWRkaW5nc1sgLCBQQ3NdCiAgICAgIGNlbGwubmFtZXMgPC0gcm93bmFtZXMoc2V1X3dkb3VibGV0c0BtZXRhLmRhdGEpCiAgICAgIG5DZWxscyA8LSBsZW5ndGgoY2VsbC5uYW1lcykKICAgICAgcm0oc2V1X3dkb3VibGV0cyk7IGdjKCkKICAgIH0KCiAgICAjIyBDb21wdXRlIFBDIGRpc3RhbmNlIG1hdHJpeAogICAgcHJpbnQoIkNhbGN1bGF0aW5nIFBDIGRpc3RhbmNlIG1hdHJpeC4uLiIpCiAgICBkaXN0Lm1hdCA8LSBmaWVsZHM6OnJkaXN0KHBjYS5jb29yZCkKCiAgICAjIyBDb21wdXRlIHBBTk4KICAgIHByaW50KCJDb21wdXRpbmcgcEFOTi4uLiIpCiAgICBwQU5OIDwtIGFzLmRhdGEuZnJhbWUobWF0cml4KDBMLCBucm93ID0gbl9yZWFsLmNlbGxzLCBuY29sID0gMSkpCiAgICByb3duYW1lcyhwQU5OKSA8LSByZWFsLmNlbGxzCiAgICBjb2xuYW1lcyhwQU5OKSA8LSAicEFOTiIKICAgIGsgPC0gcm91bmQobkNlbGxzICogcEspCiAgICBmb3IgKGkgaW4gMTpuX3JlYWwuY2VsbHMpIHsKICAgICAgbmVpZ2hib3JzIDwtIG9yZGVyKGRpc3QubWF0WywgaV0pCiAgICAgIG5laWdoYm9ycyA8LSBuZWlnaGJvcnNbMjooayArIDEpXQogICAgICBuZWlnaGJvci5uYW1lcyA8LSByb3duYW1lcyhkaXN0Lm1hdClbbmVpZ2hib3JzXQogICAgICBwQU5OJHBBTk5baV0gPC0gbGVuZ3RoKHdoaWNoKG5laWdoYm9ycyA+IG5fcmVhbC5jZWxscykpL2sKICAgIH0KCiAgICBwcmludCgiQ2xhc3NpZnlpbmcgZG91YmxldHMuLiIpCiAgICBjbGFzc2lmaWNhdGlvbnMgPC0gcmVwKCJTaW5nbGV0IixuX3JlYWwuY2VsbHMpCiAgICBjbGFzc2lmaWNhdGlvbnNbb3JkZXIocEFOTiRwQU5OWzE6bl9yZWFsLmNlbGxzXSwgZGVjcmVhc2luZz1UUlVFKVsxOm5FeHBdXSA8LSAiRG91YmxldCIKICAgIHNldUBtZXRhLmRhdGFbLCBwYXN0ZSgicEFOTiIscE4scEssbkV4cCxzZXA9Il8iKV0gPC0gcEFOTltyb3duYW1lcyhzZXVAbWV0YS5kYXRhKSwgMV0KICAgIHNldUBtZXRhLmRhdGFbLCBwYXN0ZSgiREYuY2xhc3NpZmljYXRpb25zIixwTixwSyxuRXhwLHNlcD0iXyIpXSA8LSBjbGFzc2lmaWNhdGlvbnMKICAgIHJldHVybihzZXUpCiAgfQp9CiMjIHVzYWdlOiBodHRwczovL3JkcnIuaW8vZ2l0aHViL2NocmlzLW1jZ2lubmlzLXVjc2YvRG91YmxldEZpbmRlci9tYW4vZG91YmxldEZpbmRlcl92My5odG1sCiMjIHNvdXJjZTogaHR0cHM6Ly9naXRodWIuY29tL2NocmlzLW1jZ2lubmlzLXVjc2YvRG91YmxldEZpbmRlci9ibG9iL21hc3Rlci9SL2RvdWJsZXRGaW5kZXJfdjMuUgpgYGAKClJ1biBEb3VibGV0RmluZGVyCmBgYHtyfQojIHRoZSB0dXRvcmlhbCByZWNvbW1lbmRzIHVzaW5nIHRoaXMgYXMgYW4gYXBwcm94aW1hdGlvbjoKI25FeHBfcG9pIDwtIHJvdW5kKDAuMTUqbnJvdyhwYl9zZXhAbWV0YS5kYXRhKSkKI2J1dCBhIG1vcmUgYXBwcm9wcmlhdGUgYXBwcm94aW1hdGlvbiBpcyB0aGF0IHRoZSBleHBlY3RlZCBudW1iZXIgb2YgZG91YmxldHMgaXMgfjElIHBlciAxMDAwIGNlbGxzIHNvOgpuRXhwX3BvaSA8LSByb3VuZCgoMC4wMSoobnJvdyhwYl9zZXhAbWV0YS5kYXRhKS8xMDAwKSkqbnJvdyhwYl9zZXhAbWV0YS5kYXRhKSkKI3J1biBkb3VibGV0IGZpbmRlcjoKcGJfc2V4IDwtIGRvdWJsZXRGaW5kZXJfdjMocGJfc2V4LCBQQ3MgPSAxOjIxLCBwTiA9IDAuMjUsIHBLID0gMC4wMSwgbkV4cCA9IG5FeHBfcG9pLCByZXVzZS5wQU5OID0gRkFMU0UsIHNjdCA9IEZBTFNFKQpgYGAKCnJlc3VsdHMgaW46CmBgYHtyfQp0YWJsZShwYl9zZXhAbWV0YS5kYXRhJERGLmNsYXNzaWZpY2F0aW9uc18wLjI1XzAuMDFfNDQwKQpgYGAKCiMjIyBWYWxpZGF0aW9uIGFuZCB2aXN1YWxpc2F0aW9uIG9mIGRvdWJsZXRzCgp2aXN1YWxpc2Ugd2hlcmUgZG91YmxldHMgYXJlOgpgYGB7cn0KZG91YmxldC5jZWxscyA8LSBjKHJvd25hbWVzKHBiX3NleEBtZXRhLmRhdGFbcGJfc2V4QG1ldGEuZGF0YSRERi5jbGFzc2lmaWNhdGlvbnNfMC4yNV8wLjAxXzQ0MCA9PSAiRG91YmxldCIsXSkpCmQxIDwtIERpbVBsb3QocGJfc2V4LCByZWR1Y3Rpb24gPSAidW1hcCIsIGNlbGxzLmhpZ2hsaWdodCA9IGRvdWJsZXQuY2VsbHMsIHNpemVzLmhpZ2hsaWdodCA9IDIpCiNUU05FUGxvdChvYmplY3QgPSBwYl9zZXgsIGNlbGxzLmhpZ2hsaWdodCA9IGRvdWJsZXQuY2VsbHMsIGRvLnJldHVybiA9IFRSVUUsICkKZG91YmxldDEgPC0gZDEgKyBjb29yZF9maXhlZCgpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKQoKIyMgcGxvdCBjbHVzdGVycwpjbHVzdGVyX3Bsb3QgPC0gRGltUGxvdChwYl9zZXgsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiaWRlbnQiLCBsYWJlbCA9IFRSVUUpCgpkb3VibGV0MSArIGNsdXN0ZXJfcGxvdApgYGAKCmBgYHtyfQpWbG5QbG90KG9iamVjdCA9IHBiX3NleCwgZmVhdHVyZXMgPSAicEFOTl8wLjI1XzAuMDFfNDQwIiwgcHQuc2l6ZSA9IDAuMSkKYGBgCgpgYGB7cn0KIyMgZXh0cmFjdCBtZXRhIGRhdGEgY29scyBvZiBpbnRlcmVzdApkZiA8LSBwYl9zZXhAbWV0YS5kYXRhWyxjKCJSTkFfc25uX3Jlcy4xIiwiREYuY2xhc3NpZmljYXRpb25zXzAuMjVfMC4wMV80NDAiKV0KCiMjIG1ha2UgYSB0YWJsZSBmcm9tIGRvdWJsZXRzCmRmIDwtIGRhdGEuZnJhbWUocmJpbmQodGFibGUoZGYpKSkKCiMjIGFtbWVuZCByb3duYW1lcwpkZiRjbHVzdGVyIDwtIHJvd25hbWVzKGRmKQoKIyMgY2FsY3VsYXRlIHBlcmNlbnRhZ2VzIG9mIGNlbGxzIHRoYXQgYXJlIGRvdWJsZXRzCmRmJHBjX2RvdWJsZXQgPC0gKChkZlssMV0pLygoZGZbLDFdKSArIGRmWywyXSkpKjEwMAoKIyMgaW5zcGVjdAoja2FibGUoZGZbb3JkZXIoZGYkcGNfZG91YmxldCksXSkKCiMjIHBsb3QgCmdncGxvdChkYXRhPWRmLCBhZXMoeD1jbHVzdGVyLCB5PXBjX2RvdWJsZXQpKSArCiAgZ2VvbV9jb2woZmlsbD0ic3RlZWxibHVlIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiMjIyBGaWx0ZXIgZG91YmxldHMKCkl0IGRlZmluaXRlbHkgc2VlbXMgbGlrZSB0aGVyZSBhcmUgc29tZSBiaWFzZXMgaW4gZG91YmxldCBkZXRlY3Rpb24uIEZld2VyIGRvdWJsZXRzIGluIHZlcnkgZWFybHkgcmluZ3MgYW5kIGluIG1hdHVyZSBzZXhlcyBtYXkgYmUgZHVlIHRvIGEgc21hbGxlciBudW1iZXIgb2YgdGhlIHBvcHVsYXRpb24gYmVpbmcgdGhlc2UgY2VsbHMuIAoKSXQgbWF5IGFsc28gYmUgYmlvbG9naWNhbCwgdGhhdCB0aGVzZSBjZWxscyBhcmUgbGVzcyBsaWtlbHkgdG8gYXNzb2NpYXRlIHRvIG9uZSBhbm90aGVyIChhbHRob3VnaCBsZXNzIGxpa2VseSwgYXMgZG91YmxldHMgYXJlIGEgcmVzdWx0IG9mIHRoZSBwcm9iYWJpbGl0eSBvZiB0d28gY2VsbHMgYmVpbmcgY2FwdHVyZWQgaW5zaWRlIHRoZSBzYW1lIGRyb3BsZXQgdG9nZXRoZXIgYXQgYSBjZXJ0YWluIGxvYWRpbmcgY29uY2VudHJhdGlvbiwgcmF0aGVyIHRoYW4gdHdvIGNlbGxzIGFscmVhZHkgYmVpbmcgdG9nZXRoZXIgdXBvbiBkcm9wbGV0IGNhcHR1cmUpLgoKcmVtb3ZlIGRvdWJsZXRzOgpgYGB7cn0KIyMgbWFrZSBhIGxpc3Qgb2Ygc2luZ2xldCBjZWxscwprZWVwX3NpbmdsZXRzIDwtIHJvd25hbWVzKHBiX3NleEBtZXRhLmRhdGFbcGJfc2V4QG1ldGEuZGF0YSRERi5jbGFzc2lmaWNhdGlvbnNfMC4yNV8wLjAxXzQ0MCA9PSAiU2luZ2xldCIsXSkKCiMjIHN1YnNldCBpbnRvIG5ldyBzZXVyYXQgb2JqZWN0CnBiX3NleF9maWx0ZXJlZCA8LSBzdWJzZXQocGJfc2V4LCBjZWxscyA9IGtlZXBfc2luZ2xldHMsIHN1YnNldC5yYXcgPSBUUlVFKQoKIyMgY29tcGFyZSBvbGQgYW5kIG5ldyBvYmplY3RzCnBiX3NleApwYl9zZXhfZmlsdGVyZWQKYGBgCgojIDcuIExpZmUgQ3ljbGUgU3RhZ2UgKFVzaW5nIEJ1bGsgUk5BLVNlcSBDb3JyZWxhdGlvbikgey50YWJzZXR9CgpBZGQgaW4gYnVsayBkYXRhIHByZWRpY3Rpb25zCgojIyMgaG9vIGV0IGFsLgpgYGB7cn0KI1BiIFByZWRpY3Rpb24gY29ycmVsYXRpb25zIHdpdGggYnVsayBkYXRhIChhc2V4dWFsIGhvbyk6IAoKI0xvYWQgaW4gcmVxdWlyZWQgcGFja2FnZToKbGlicmFyeShIbWlzYykKI0Nvb2VyY2UgZXhwcmVzc2lvbiBkYXRhIGludG8gYSBtYXRyaXggYW5kIGxvYWQgaW4gdGhlIHJlZmVyZW5jZSB0aW1lY291cnNlIGRhdGE6CngxMCA8LSBhcy5tYXRyaXgocGJfc2V4X2ZpbHRlcmVkQGFzc2F5cyRSTkFAZGF0YSkKcm93bmFtZXMoeDEwKSA8LSBnc3ViKCItIiwgIl8iLCByb3duYW1lcyh4MTApKQojcmVhZCBpbiBidWxrIGRhdGE6CmhvbzwtYXMubWF0cml4KHJlYWQudGFibGUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhL1JlZmVyZW5jZS9ob29fYmVyZzIudHh0IixoZWFkZXI9VCwgcm93Lm5hbWVzPTEpKQojTWFrZSBhIGJsYW5rIGRhdGFmcmFtZSBpbiB3aGljaCB0byBhZGQgcHJlZGljdGlvbjoKZGYgPC0gZGF0YS5mcmFtZShtYXRyaXgobmNvbCA9IDQsIG5yb3cgPSAwKSkKY29sbmFtZXMoZGYpIDwtIGMoIlByZWRpY3Rpb24oU3BlYXJtYW4pIiwicihTcGVhcm1hbikiLCJQcmVkaWN0aW9uKFBlYXJzb25zKSIsInIoUGVhcnNvbnMpIikKI0RvIGNvcnJlbGF0aW9ucyB3aXRoIGJ1bGsgZGF0YSB1c2luZyBib3RoIFNwZWFybWFuIGFuZCBQZWFyc29uIChhbmQgdGhlIHRvcCAxMDAwIGdlbmVzKToKZm9yIChpIGluIDE6bmNvbCh4MTApKQp7CiAgc2hhcmVkPC1pbnRlcnNlY3Qocm93Lm5hbWVzKGFzLm1hdHJpeChoZWFkKHNvcnQoeDEwWyxpXSwgZGVjcmVhc2luZz1UUlVFKSwxMDAwKSkpLHJvdy5uYW1lcyhob28pKQogIHN0ZXAwPC1yY29ycih4MTBbc2hhcmVkLGldLGhvb1tzaGFyZWQsMToxMl0sdHlwZSA9ICJzcGVhcm1hbiIpCiAgc3RlcDE8LWFzLm1hdHJpeCh0KHN0ZXAwJHJbMjoxMywxXSkpCiAgc3RlcDI8LXJjb3JyKHgxMFtzaGFyZWQsaV0saG9vW3NoYXJlZCwxOjEyXSx0eXBlID0gInBlYXJzb24iKQogIHN0ZXAzPC1hcy5tYXRyaXgodChzdGVwMiRyWzI6MTMsMV0pKQogIHN0ZXA0PC1jYmluZChjb2xuYW1lcyhzdGVwMSlbd2hpY2gubWF4KHN0ZXAxKV0sc3RlcDFbd2hpY2gubWF4KHN0ZXAxKV0sY29sbmFtZXMoc3RlcDMpW3doaWNoLm1heChzdGVwMyldLHN0ZXAzW3doaWNoLm1heChzdGVwMyldKQogIGNvbG5hbWVzKHN0ZXA0KSA8LSBjKCJQcmVkaWN0aW9uKFNwZWFybWFuKSIsInIoU3BlYXJtYW4pIiwiUHJlZGljdGlvbihQZWFyc29ucykiLCJyKFBlYXJzb25zKSIpCiAgcm93bmFtZXMoc3RlcDQpPC1jb2xuYW1lcyh4MTApW2ldCiAgZGY8LXJiaW5kKGRmLHN0ZXA0KQp9CiNXcml0ZSBvdXQgZGF0YSBpbnRvIGEgY3N2IGZpbGU6CiN3cml0ZS5jc3YoZGZyaW5ncixmaWxlPSIvVXNlcnMvYXIxOS9EZXNrdG9wL1BoRC9BUjA0X0dDU0tPX3Byb2plY3QvQWxsX211dGFudHNfRmViXzIwMTgvcHJlZGljdGlvbnBiY29tYmluZWQuY3N2IikKI0NoYW5nZSB0aGUgZm9ybWF0IG9mIHRoZSBvdXRwdXQgdG8gbWFrZSBpdCBtb3JlIHJlYWRhYmxlOgojZ3N1YigiUGJfIiwiIiwgZGZyaW5nclssMV0pIC0gTWFrZSBwcmVkaWN0aW9ucyBpbnRvIDE4aHIuZGF0IGZvcm1hdDoKCiNzcGVhcm1hbjoKZGZbLDFdIDwtIGdzdWIoIlBiXyIsIiIsIGRmWywxXSkKI1JlbW92ZSBoci5kYXQgZnJvbSBsaXN0OgpkZlssMV0gPC0gZ3N1YigiaHIuZGF0IiwiIiwgZGZbLDFdKQojQ2hlY2sgLSBkZnJpbmdyWywxXQojTWFrZSBpbnRvIGEgbnVtYmVyOgpkZlssMV0gPC0gYXMubnVtZXJpYyhkZlssMV0pCmRmWywyXSA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkZlssMl0pKQoKI3BlYXJzb246CmRmWywzXSA8LSBnc3ViKCJQYl8iLCIiLCBkZlssM10pCiNSZW1vdmUgaHIuZGF0IGZyb20gbGlzdDoKZGZbLDNdIDwtIGdzdWIoImhyLmRhdCIsIiIsIGRmWywzXSkKI0NoZWNrIC0gZGZyaW5nclssMV0KI01ha2UgaW50byBhIG51bWJlcjoKZGZbLDNdIDwtIGFzLm51bWVyaWMoZGZbLDNdKQpkZlssNF0gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZGZbLDRdKSkKI2FkZCB0byAxMFggb2JqZWN0OgpwYl9zZXhfZmlsdGVyZWQgPC0gQWRkTWV0YURhdGEocGJfc2V4X2ZpbHRlcmVkLCBtZXRhZGF0YSA9IGRmKQpgYGAKCiMjIyBLYXNpYSdzIGRhdGEKQ2FuIGFsc28gZG8gd2l0aCBLYXNpYSdzIHRpbWVjb3Vyc2UgZGF0YToKYGBge3J9CmthczwtYXMubWF0cml4KHJlYWQudGFibGUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhL1JlZmVyZW5jZS9BUDJPRVRDLnR4dCIsaGVhZGVyPVQsIHJvdy5uYW1lcz0xKSkKI01ha2UgYSBibGFuayBkYXRhZnJhbWUgaW4gd2hpY2ggdG8gYWRkIHByZWRpY3Rpb246CmRmcyA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sID0gNCwgbnJvdyA9IDApKQpjb2xuYW1lcyhkZnMpIDwtIGMoIklEIiwiUHJlZGljdGlvbiIsInIgKFBlYXJzb24pIikKI0RvIGNvcnJlbGF0aW9ucyB3aXRoIGJ1bGsgZGF0YSB1c2luZyBib3RoIFNwZWFybWFuIGFuZCBQZWFyc29uIChhbmQgdGhlIHRvcCAxMDAwIGdlbmVzKToKZm9yIChpIGluIDE6bmNvbCh4MTApKQp7CiAgc2hhcmVkPC1pbnRlcnNlY3Qocm93Lm5hbWVzKGFzLm1hdHJpeChoZWFkKHNvcnQoeDEwWyxpXSwgZGVjcmVhc2luZz1UUlVFKSwxMDAwKSkpLHJvd25hbWVzKGthcykpCiAgc3RlcDA8LXJjb3JyKHgxMFtzaGFyZWQsaV0sa2FzW3NoYXJlZCwxOjEwXSx0eXBlID0gInNwZWFybWFuIikKICBzdGVwMTwtYXMubWF0cml4KHQoc3RlcDAkclsyOjExLDFdKSkKICBzdGVwMjwtcmNvcnIoeDEwW3NoYXJlZCxpXSxrYXNbc2hhcmVkLDE6MTBdLHR5cGUgPSAicGVhcnNvbiIpCiAgc3RlcDM8LWFzLm1hdHJpeCh0KHN0ZXAyJHJbMjoxMSwxXSkpCiAgc3RlcDQ8LWNiaW5kKGNvbG5hbWVzKHN0ZXAxKVt3aGljaC5tYXgoc3RlcDEpXSxzdGVwMVt3aGljaC5tYXgoc3RlcDEpXSxjb2xuYW1lcyhzdGVwMylbd2hpY2gubWF4KHN0ZXAzKV0sc3RlcDNbd2hpY2gubWF4KHN0ZXAzKV0pCiAgY29sbmFtZXMoc3RlcDQpIDwtIGMoIlByZWRpY3Rpb24oU3BlYXJtYW4pIiwicihTcGVhcm1hbikiLCJQcmVkaWN0aW9uKFBlYXJzb25zKSIsInIoUGVhcnNvbnMpIikKICByb3duYW1lcyhzdGVwNCk8LWNvbG5hbWVzKHgxMClbaV0KICBkZnM8LXJiaW5kKGRmcyxzdGVwNCkKfQojV3JpdGUgb3V0IGRhdGEgaW50byBhIGNzdiBmaWxlOgojd3JpdGUuY3N2KGRmLGZpbGU9Ii9Vc2Vycy9hcjE5L0Rlc2t0b3AvUGhEL0FSMDRfR0NTS09fcHJvamVjdC9BbGxfbXV0YW50c19GZWJfMjAxOC9wcmVkaWN0aW9ua2FzaWFjb21iaW5lZC5jc3YiKQoKI0NoYW5nZSB0aGUgZm9ybWF0IG9mIHRoZSBvdXRwdXQgdG8gbWFrZSBpdCBtb3JlIHJlYWRhYmxlOgojZ3N1YigiUGJfIiwiIiwgZGZzWywxXSkgLSBNYWtlIHByZWRpY3Rpb25zIGludG8gMThoci5kYXQgZm9ybWF0OgpkZnNbLDFdIDwtIGdzdWIoIlgiLCIiLCBkZnNbLDFdKQojTWFrZSBpbnRvIGEgbnVtYmVyOgpkZnNbLDFdIDwtIGFzLm51bWVyaWMoZGZzWywxXSkKI01ha2UgaW50byBhIG51bWJlcjoKZGZzWywyXSA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkZnNbLDJdKSkKCiNnc3ViKCJQYl8iLCIiLCBkZnNbLDFdKSAtIE1ha2UgcHJlZGljdGlvbnMgaW50byAxOGhyLmRhdCBmb3JtYXQ6CmRmc1ssM10gPC0gZ3N1YigiWCIsIiIsIGRmc1ssM10pCiNNYWtlIGludG8gYSBudW1iZXI6CmRmc1ssM10gPC0gYXMubnVtZXJpYyhkZnNbLDNdKQojZGZzWywxXQojTWFrZSBpbnRvIGEgbnVtYmVyOgpkZnNbLDRdIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGRmc1ssNF0pKQoKY29sbmFtZXMoZGZzKSA8LSBjKCdQcmVkaWN0aW9uKFNwZWFybWFuKV9LYXNpYScsICdyKFNwZWFybWFuKV9LYXNpYScsICdQcmVkaWN0aW9uKFBlYXJzb24pX0thc2lhJywgJ3IoUGVhcnNvbilfS2FzaWEnKQojYWRkIHRvIFNldXJhdDoKI2FkZCB0byAxMFggb2JqZWN0OgpwYl9zZXhfZmlsdGVyZWQgPC0gQWRkTWV0YURhdGEocGJfc2V4X2ZpbHRlcmVkLCBkZnMpCmBgYAoKIyMjIFZpc3VhbGlzZQoKQ29uZmlybSBsaWZlIGN5Y2xlIGRlc2lnbmF0aW9uczoKYGBge3J9CiMjIHBsb3QKRmVhdHVyZVBsb3QocGJfc2V4X2ZpbHRlcmVkLCBmZWF0dXJlcyA9IGMoIlByZWRpY3Rpb24uU3BlYXJtYW4uX0thc2lhIiwgIlByZWRpY3Rpb24uU3BlYXJtYW4uIikpCmBgYAoKb3B0aW1zZSBVTUFQCmBgYHtyfQojIyBQQ0EgY2FsYwpwYl9zZXhfZmlsdGVyZWQgPC0gUnVuUENBKHBiX3NleF9maWx0ZXJlZCwgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IHBiX3NleF9maWx0ZXJlZCkpCgojIyBlbGJvdyBwbG90CkVsYm93UGxvdChwYl9zZXhfZmlsdGVyZWQsIG5kaW1zID0gMzAsIHJlZHVjdGlvbiA9ICJwY2EiKQoKIyMgVU1BUCBjYWxjCnBiX3NleF9maWx0ZXJlZCA8LSBSdW5VTUFQKHBiX3NleF9maWx0ZXJlZCwgZGltcyA9IDE6OCwgc2VlZC51c2UgPSAzMDAsIG4ubmVpZ2hib3JzID0gNjAsIG1pbi5kaXN0ID0gMC41LCByZXB1bHNpb24uc3RyZW5ndGggPSAwLjA1LCBsb2NhbC5jb25uZWN0aXZpdHkgPSAyMCkKCiMjIFVNQVAgcGxvdApEaW1QbG90KHBiX3NleF9maWx0ZXJlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJpZGVudCIsIGxhYmVsID0gVFJVRSkKYGBgCgoKIyA4LiBTYXZlIGFuZCBFeHBvcnQgey50YWJzZXR9CgpTYXZlIGVudmlyb25tZW50CmBgYHtyfQojIyBUaGlzIHNhdmVzIGV2ZXJ5dGhpbmcgaW4gdGhlIGdsb2JhbCBlbnZpcm9ubWVudCBmb3IgZWFzeSByZWNhbGwgbGF0ZXIKI3NhdmUuaW1hZ2UoZmlsZSA9ICJHQ1NLT18xMFhfUUMuUkRhdGEiKQojbG9hZChmaWxlID0gIkdDU0tPXzEwWF9RQy5SRGF0YSIpCmBgYAoKU2F2ZSBvYmplY3QocykKYGBge3J9CiMjIHNhdmUgUmRhdGEKI3NhdmUocGJfMzBrX3NleF9maWx0ZXJlZCwgcGJfc2V4X2ZpbHRlcmVkLCBmaWxlID0gIlBhcnRfMl9pbnB1dC5SZGF0YSIpCiNsb2FkKGZpbGUgPSAiUGFydF8yX2lucHV0LlJkYXRhIikKCiMjIHNhdmUgUkRTCnNhdmVSRFMocGJfc2V4X2ZpbHRlcmVkLCBmaWxlID0gIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhX3RvX2V4cG9ydC9wYl9zZXhfZmlsdGVyZWQuUkRTIiwgY29tcHJlc3MgPSBGQUxTRSkgCiNwYl9zZXhfZmlsdGVyZWQgPC0gcmVhZFJEUygicGJfc2V4X2ZpbHRlcmVkLlJEUyIpCgojIyBTYXZlIFJvYmoKI3NhdmUocGJfc2V4X2ZpbHRlcmVkLGZpbGU9InBiX3NleF9maWx0ZXJlZC5Sb2JqIikKYGBgCgojIEFwcGVuZGl4IHsudGFic2V0fQoKIyMgU2Vzc2lvbiBJbmZvIApgYGB7ciwgZWNobyA9IEZBTFNFfQpzZXNzaW9uSW5mbygpCmBgYAo=